Skip to content

Commit 0faa1c7

Browse files
author
Abduqodiri Qurbonzoda
committed
Support null element and fail-fast iterator in OrderedSet and Builder
1 parent 4b67bef commit 0faa1c7

File tree

4 files changed

+75
-45
lines changed

4 files changed

+75
-45
lines changed

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet.kt

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,24 @@ package kotlinx.collections.immutable.implementations.persistentOrderedSet
1818

1919
import kotlinx.collections.immutable.PersistentSet
2020
import kotlinx.collections.immutable.implementations.immutableMap.PersistentHashMap
21+
import kotlinx.collections.immutable.implementations.persistentOrderedMap.EndOfLink
2122
import kotlinx.collections.immutable.mutate
2223

23-
internal class Links<out E>(val previous: E?, val next: E?)
24+
internal class Links(val previous: Any?, val next: Any?) {
25+
constructor() : this(EndOfLink, EndOfLink)
26+
27+
fun withNext(newNext: Any?) = Links(previous, newNext)
28+
fun withPrevious(newPrevious: Any?) = Links(newPrevious, next)
29+
30+
fun putNextLink(previous: Any?): Links {
31+
// assert(next === EndOfLink)
32+
return Links(previous, next)
33+
}
34+
}
2435

2536
internal class PersistentOrderedSet<E>(internal val firstElement: E?,
2637
internal val lastElement: E?,
27-
internal val map: PersistentHashMap<E, Links<E>>): AbstractSet<E>(), PersistentSet<E> {
38+
internal val map: PersistentHashMap<E, Links>): AbstractSet<E>(), PersistentSet<E> {
2839

2940
override val size: Int
3041
get() = map.size
@@ -37,14 +48,16 @@ internal class PersistentOrderedSet<E>(internal val firstElement: E?,
3748
if (map.containsKey(element)) {
3849
return this
3950
}
40-
if (lastElement == null) { // isEmpty
41-
val newMap = map.put(element, Links<E>(null, null))
51+
if (isEmpty()) { // isEmpty
52+
val newMap = map.put(element, Links())
4253
return PersistentOrderedSet(element, element, newMap)
4354
}
44-
val oldLinks = map[lastElement]!!
45-
assert(oldLinks.next == null)
46-
val newLinks = Links(oldLinks.previous, element)
47-
val newMap = map.put(lastElement, newLinks).put(element, Links(lastElement, null))
55+
val lastLinks = map[lastElement]!!
56+
// assert(lastLinks.next === EndOfLink)
57+
58+
val newMap = map
59+
.put(lastElement as E, lastLinks.withNext(element))
60+
.put(element, lastLinks.putNextLink(lastElement))
4861
return PersistentOrderedSet(firstElement, element, newMap)
4962
}
5063

@@ -56,18 +69,18 @@ internal class PersistentOrderedSet<E>(internal val firstElement: E?,
5669
val links = map[element] ?: return this
5770

5871
var newMap = map.remove(element)
59-
if (links.previous != null) {
72+
if (links.previous !== EndOfLink) {
6073
val previousLinks = newMap[links.previous]!!
61-
assert(previousLinks.next == element)
62-
newMap = newMap.put(links.previous, Links(previousLinks.previous, links.next))
74+
// assert(previousLinks.next == element)
75+
newMap = newMap.put(links.previous as E, previousLinks.withNext(links.next))
6376
}
64-
if (links.next != null) {
77+
if (links.next !== EndOfLink) {
6578
val nextLinks = newMap[links.next]!!
66-
assert(nextLinks.previous == element)
67-
newMap = newMap.put(links.next, Links(links.previous, nextLinks.next))
79+
// assert(nextLinks.previous == element)
80+
newMap = newMap.put(links.next as E, nextLinks.withPrevious(links.previous))
6881
}
69-
val newFirstElement = if (element == firstElement) links.next else firstElement
70-
val newLastElement = if (element == lastElement) links.previous else lastElement
82+
val newFirstElement = if (links.previous === EndOfLink) links.next as? E else firstElement
83+
val newLastElement = if (links.next === EndOfLink) links.previous as? E else lastElement
7184
return PersistentOrderedSet(newFirstElement, newLastElement, newMap)
7285
}
7386

@@ -92,7 +105,7 @@ internal class PersistentOrderedSet<E>(internal val firstElement: E?,
92105
}
93106

94107
internal companion object {
95-
private val EMPTY = PersistentOrderedSet<Nothing>(null, null, PersistentHashMap.emptyOf<Nothing, Links<Nothing>>())
108+
private val EMPTY = PersistentOrderedSet(null, null, PersistentHashMap.emptyOf())
96109
internal fun <E> emptyOf(): PersistentSet<E> = EMPTY
97110
}
98111
}

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSetBuilder.kt

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package kotlinx.collections.immutable.implementations.persistentOrderedSet
1818

1919
import kotlinx.collections.immutable.PersistentSet
20+
import kotlinx.collections.immutable.implementations.persistentOrderedMap.EndOfLink
2021

2122
internal class PersistentOrderedSetBuilder<E>(private var set: PersistentOrderedSet<E>) : AbstractMutableSet<E>(), PersistentSet.Builder<E> {
2223
internal var firstElement = set.firstElement
@@ -46,37 +47,38 @@ internal class PersistentOrderedSetBuilder<E>(private var set: PersistentOrdered
4647
if (mapBuilder.containsKey(element)) {
4748
return false
4849
}
49-
if (lastElement == null) { // isEmpty
50+
if (isEmpty()) { // isEmpty
5051
firstElement = element
5152
lastElement = element
52-
mapBuilder[element] = Links<E>(null, null)
53+
mapBuilder[element] = Links()
5354
return true
5455
}
55-
val oldLinks = mapBuilder[lastElement!!]!!
56-
assert(oldLinks.next == null)
57-
val newLinks = Links(oldLinks.previous, element)
56+
val lastLinks = mapBuilder[lastElement]!!
57+
// assert(lastLinks.next === EndOfLink)
5858

59-
mapBuilder[lastElement!!] = newLinks
60-
mapBuilder[element] = Links(lastElement, null)
59+
mapBuilder[lastElement as E] = lastLinks.withNext(element)
60+
mapBuilder[element] = lastLinks.putNextLink(lastElement)
6161
lastElement = element
6262
return true
6363
}
6464

6565
override fun remove(element: E): Boolean {
6666
val links = mapBuilder.remove(element) ?: return false
6767

68-
if (links.previous != null) {
68+
if (links.previous !== EndOfLink) {
6969
val previousLinks = mapBuilder[links.previous]!!
70-
assert(previousLinks.next == element)
71-
mapBuilder[links.previous] = Links(previousLinks.previous, links.next)
70+
// assert(previousLinks.next == element)
71+
mapBuilder[links.previous as E] = previousLinks.withNext(links.next)
72+
} else {
73+
firstElement = links.next as? E
7274
}
73-
if (links.next != null) {
75+
if (links.next !== EndOfLink) {
7476
val nextLinks = mapBuilder[links.next]!!
75-
assert(nextLinks.previous == element)
76-
mapBuilder[links.next] = Links(links.previous, nextLinks.next)
77+
// assert(nextLinks.previous == element)
78+
mapBuilder[links.next as E] = nextLinks.withPrevious(links.previous)
79+
} else {
80+
lastElement = links.previous as? E
7781
}
78-
firstElement = if (element == firstElement) links.next else firstElement
79-
lastElement = if (element == lastElement) links.previous else lastElement
8082
return true
8183
}
8284

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSetIterator.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,24 @@
1717
package kotlinx.collections.immutable.implementations.persistentOrderedSet
1818

1919
internal open class PersistentOrderedSetIterator<E>(private var nextElement: E?,
20-
internal val map: Map<E, Links<E>>) : Iterator<E> {
20+
internal val map: Map<E, Links>) : Iterator<E> {
2121
internal var index = 0
2222

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

2727
override fun next(): E {
28-
if (!hasNext())
29-
throw NoSuchElementException()
28+
checkHasNext()
3029

3130
val result = nextElement as E
3231
index++
33-
nextElement = map[result]!!.next
32+
nextElement = map[result]!!.next as? E
3433
return result
3534
}
35+
36+
private fun checkHasNext() {
37+
if (!hasNext())
38+
throw NoSuchElementException()
39+
}
3640
}

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSetMutableIterator.kt

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,34 @@ package kotlinx.collections.immutable.implementations.persistentOrderedSet
1919
internal class PersistentOrderedSetMutableIterator<E>(private val builder: PersistentOrderedSetBuilder<E>)
2020
: PersistentOrderedSetIterator<E>(builder.firstElement, builder.mapBuilder), MutableIterator<E> {
2121

22-
var lastReturned: E? = null
23-
var nextWasInvoked = false
22+
private var lastIteratedElement: E? = null
23+
private var nextWasInvoked = false
24+
private var expectedModCount = builder.mapBuilder.modCount
2425

2526
override fun next(): E {
27+
checkForComodification()
2628
val next = super.next()
27-
lastReturned = next
29+
lastIteratedElement = next
2830
nextWasInvoked = true
2931
return next
3032
}
3133

3234
override fun remove() {
33-
if (!nextWasInvoked) {
34-
throw NoSuchElementException()
35-
}
36-
builder.remove(lastReturned)
37-
index--
38-
lastReturned = null
35+
checkNextWasInvoked()
36+
builder.remove(lastIteratedElement)
37+
lastIteratedElement = null
3938
nextWasInvoked = false
39+
expectedModCount = builder.mapBuilder.modCount
40+
index--
41+
}
42+
43+
private fun checkNextWasInvoked() {
44+
if (!nextWasInvoked)
45+
throw IllegalStateException()
46+
}
47+
48+
private fun checkForComodification() {
49+
if (builder.mapBuilder.modCount != expectedModCount)
50+
throw ConcurrentModificationException()
4051
}
4152
}

0 commit comments

Comments
 (0)