Skip to content

Commit 240eb44

Browse files
committed
fix: compose ios concurrent modification fix for 1.9
1 parent acad7f0 commit 240eb44

File tree

7 files changed

+110
-100
lines changed

7 files changed

+110
-100
lines changed

voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/model/ScreenModelStore.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public object ScreenModelStore : ScreenDisposable {
114114

115115
private fun Map<String, *>.onEachHolder(holderKey: String, block: (String) -> Unit) =
116116
toMap() // copy
117+
.asSequence()
117118
.filter { it.key.startsWith(holderKey) }
118119
.map { it.key }
119120
.forEach(block)

voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.native.kt

Lines changed: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,12 @@ package cafe.adriel.voyager.core.concurrent
33
import kotlinx.atomicfu.locks.SynchronizedObject
44
import kotlinx.atomicfu.locks.synchronized
55

6-
public actual class ThreadSafeList<T>(
6+
public actual class ThreadSafeList<T> internal constructor(
7+
private val syncObject: SynchronizedObject,
78
private val delegate: MutableList<T>
8-
) : MutableList<T> {
9+
) : MutableList<T>, ThreadSafeMutableCollection<T>(syncObject, delegate) {
910
public actual constructor() : this(delegate = mutableListOf())
10-
private val syncObject = SynchronizedObject()
11-
12-
override val size: Int
13-
get() = delegate.size
14-
15-
override fun contains(element: T): Boolean {
16-
return synchronized(syncObject) { delegate.contains(element) }
17-
}
18-
19-
override fun containsAll(elements: Collection<T>): Boolean {
20-
return synchronized(syncObject) { delegate.containsAll(elements) }
21-
}
11+
public constructor(delegate: MutableList<T>) : this(SynchronizedObject(), delegate)
2212

2313
override fun get(index: Int): T {
2414
return synchronized(syncObject) { delegate.get(index) }
@@ -28,22 +18,10 @@ public actual class ThreadSafeList<T>(
2818
return synchronized(syncObject) { delegate.indexOf(element) }
2919
}
3020

31-
override fun isEmpty(): Boolean {
32-
return synchronized(syncObject) { delegate.isEmpty() }
33-
}
34-
35-
override fun iterator(): MutableIterator<T> {
36-
return synchronized(syncObject) { delegate.iterator() }
37-
}
38-
3921
override fun lastIndexOf(element: T): Int {
4022
return synchronized(syncObject) { delegate.lastIndexOf(element) }
4123
}
4224

43-
override fun add(element: T): Boolean {
44-
return synchronized(syncObject) { delegate.add(element) }
45-
}
46-
4725
override fun add(index: Int, element: T) {
4826
return synchronized(syncObject) { delegate.add(index, element) }
4927
}
@@ -52,43 +30,23 @@ public actual class ThreadSafeList<T>(
5230
return synchronized(syncObject) { delegate.addAll(index, elements) }
5331
}
5432

55-
override fun addAll(elements: Collection<T>): Boolean {
56-
return synchronized(syncObject) { delegate.addAll(elements) }
57-
}
58-
59-
override fun clear() {
60-
return synchronized(syncObject) { delegate.clear() }
61-
}
62-
6333
override fun listIterator(): MutableListIterator<T> {
64-
return synchronized(syncObject) { delegate.listIterator() }
34+
return synchronized(syncObject) { ThreadSafeMutableListIterator(syncObject, delegate.listIterator()) }
6535
}
6636

6737
override fun listIterator(index: Int): MutableListIterator<T> {
68-
return synchronized(syncObject) { delegate.listIterator(index) }
69-
}
70-
71-
override fun remove(element: T): Boolean {
72-
return synchronized(syncObject) { delegate.remove(element) }
73-
}
74-
75-
override fun removeAll(elements: Collection<T>): Boolean {
76-
return synchronized(syncObject) { delegate.removeAll(elements) }
38+
return synchronized(syncObject) { ThreadSafeMutableListIterator(syncObject, delegate.listIterator(index)) }
7739
}
7840

7941
override fun removeAt(index: Int): T {
8042
return synchronized(syncObject) { delegate.removeAt(index) }
8143
}
8244

83-
override fun retainAll(elements: Collection<T>): Boolean {
84-
return synchronized(syncObject) { delegate.retainAll(elements) }
85-
}
86-
8745
override fun set(index: Int, element: T): T {
8846
return synchronized(syncObject) { delegate.set(index, element) }
8947
}
9048

9149
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> {
92-
return synchronized(syncObject) { delegate.subList(fromIndex, toIndex) }
50+
return synchronized(syncObject) { ThreadSafeList(syncObject, delegate.subList(fromIndex, toIndex)) }
9351
}
9452
}

voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.native.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ public actual class ThreadSafeMap<K, V>(
2929
}
3030

3131
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
32-
get() = synchronized(syncObject) { delegate.entries.toMutableSet() }
32+
get() = synchronized(syncObject) { ThreadSafeSet(syncObject, delegate.entries) }
3333
override val keys: MutableSet<K>
34-
get() = synchronized(syncObject) { delegate.keys.toMutableSet() }
34+
get() = synchronized(syncObject) { ThreadSafeSet(syncObject, delegate.keys) }
3535
override val values: MutableCollection<V>
36-
get() = synchronized(syncObject) { delegate.values.toMutableList() }
36+
get() = synchronized(syncObject) { ThreadSafeMutableCollection(syncObject, delegate.values) }
3737

3838
override fun clear() {
3939
synchronized(syncObject) { delegate.clear() }
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package cafe.adriel.voyager.core.concurrent
2+
3+
import kotlinx.atomicfu.locks.SynchronizedObject
4+
import kotlinx.atomicfu.locks.synchronized
5+
6+
public open class ThreadSafeMutableCollection<T>internal constructor(
7+
private val syncObject: SynchronizedObject,
8+
private val delegate: MutableCollection<T>
9+
) : MutableCollection<T> {
10+
11+
override val size: Int
12+
get() = synchronized(syncObject) { delegate.size }
13+
14+
override fun contains(element: T): Boolean {
15+
return synchronized(syncObject) { delegate.contains(element) }
16+
}
17+
18+
override fun containsAll(elements: Collection<T>): Boolean {
19+
return synchronized(syncObject) { delegate.containsAll(elements) }
20+
}
21+
22+
override fun isEmpty(): Boolean {
23+
return synchronized(syncObject) { delegate.isEmpty() }
24+
}
25+
26+
override fun iterator(): MutableIterator<T> {
27+
return synchronized(syncObject) { ThreadSafeMutableIterator(syncObject, delegate.iterator()) }
28+
}
29+
30+
override fun add(element: T): Boolean {
31+
return synchronized(syncObject) { delegate.add(element) }
32+
}
33+
34+
override fun addAll(elements: Collection<T>): Boolean {
35+
return synchronized(syncObject) { delegate.addAll(elements) }
36+
}
37+
38+
override fun clear() {
39+
return synchronized(syncObject) { delegate.clear() }
40+
}
41+
42+
override fun remove(element: T): Boolean {
43+
return synchronized(syncObject) { delegate.remove(element) }
44+
}
45+
46+
override fun removeAll(elements: Collection<T>): Boolean {
47+
return synchronized(syncObject) { delegate.removeAll(elements) }
48+
}
49+
50+
override fun retainAll(elements: Collection<T>): Boolean {
51+
return synchronized(syncObject) { delegate.retainAll(elements) }
52+
}
53+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package cafe.adriel.voyager.core.concurrent
2+
3+
import kotlinx.atomicfu.locks.SynchronizedObject
4+
import kotlinx.atomicfu.locks.synchronized
5+
6+
internal open class ThreadSafeMutableIterator<E>(
7+
private val syncObject: SynchronizedObject,
8+
private val delegate: MutableIterator<E>
9+
) : MutableIterator<E> {
10+
override fun hasNext(): Boolean = synchronized(syncObject) { delegate.hasNext() }
11+
12+
override fun next(): E = synchronized(syncObject) { delegate.next() }
13+
14+
override fun remove() {
15+
synchronized(syncObject) { delegate.remove() }
16+
}
17+
}
18+
19+
internal class ThreadSafeMutableListIterator<E>(
20+
private val syncObject: SynchronizedObject,
21+
private val delegate: MutableListIterator<E>
22+
) : ThreadSafeMutableIterator<E>(syncObject, delegate),
23+
MutableListIterator<E> {
24+
25+
override fun hasPrevious(): Boolean = synchronized(syncObject) { delegate.hasPrevious() }
26+
27+
override fun nextIndex(): Int = synchronized(syncObject) { delegate.nextIndex() }
28+
29+
override fun previous(): E = synchronized(syncObject) { delegate.previous() }
30+
31+
override fun previousIndex(): Int = synchronized(syncObject) { delegate.previousIndex() }
32+
33+
override fun add(element: E) {
34+
synchronized(syncObject) { delegate.add(element) }
35+
}
36+
37+
override fun set(element: E) {
38+
synchronized(syncObject) { delegate.set(element) }
39+
}
40+
}

voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.native.kt

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,9 @@ import kotlinx.atomicfu.locks.SynchronizedObject
44
import kotlinx.atomicfu.locks.synchronized
55

66
public actual class ThreadSafeSet<T>(
7-
private val delegate: MutableSet<T>
8-
) : MutableSet<T> {
7+
syncObject: SynchronizedObject,
8+
delegate: MutableSet<T>
9+
) : MutableSet<T>, ThreadSafeMutableCollection<T>(syncObject, delegate) {
910
public actual constructor() : this(delegate = mutableSetOf())
10-
private val syncObject = SynchronizedObject()
11-
12-
override val size: Int
13-
get() = delegate.size
14-
15-
override fun contains(element: T): Boolean {
16-
return synchronized(syncObject) { delegate.contains(element) }
17-
}
18-
19-
override fun containsAll(elements: Collection<T>): Boolean {
20-
return synchronized(syncObject) { delegate.containsAll(elements) }
21-
}
22-
23-
override fun isEmpty(): Boolean {
24-
return synchronized(syncObject) { delegate.isEmpty() }
25-
}
26-
27-
override fun iterator(): MutableIterator<T> {
28-
return synchronized(syncObject) { delegate.iterator() }
29-
}
30-
31-
override fun add(element: T): Boolean {
32-
return synchronized(syncObject) { delegate.add(element) }
33-
}
34-
35-
override fun addAll(elements: Collection<T>): Boolean {
36-
return synchronized(syncObject) { delegate.addAll(elements) }
37-
}
38-
39-
override fun clear() {
40-
return synchronized(syncObject) { delegate.clear() }
41-
}
42-
43-
override fun remove(element: T): Boolean {
44-
return synchronized(syncObject) { delegate.remove(element) }
45-
}
46-
47-
override fun removeAll(elements: Collection<T>): Boolean {
48-
return synchronized(syncObject) { delegate.removeAll(elements) }
49-
}
50-
51-
override fun retainAll(elements: Collection<T>): Boolean {
52-
return synchronized(syncObject) { delegate.retainAll(elements) }
53-
}
11+
public constructor(delegate: MutableSet<T>) : this(SynchronizedObject(), delegate)
5412
}

voyager-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/Navigator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import cafe.adriel.voyager.core.lifecycle.MultipleProvideBeforeScreenContent
1717
import cafe.adriel.voyager.core.lifecycle.ScreenLifecycleStore
1818
import cafe.adriel.voyager.core.lifecycle.getNavigatorScreenLifecycleProvider
1919
import cafe.adriel.voyager.core.lifecycle.rememberScreenLifecycleOwner
20-
import cafe.adriel.voyager.core.model.ScreenModelStore
2120
import cafe.adriel.voyager.core.screen.Screen
2221
import cafe.adriel.voyager.core.stack.Stack
2322
import cafe.adriel.voyager.core.stack.toMutableStateStack
@@ -179,7 +178,8 @@ public class Navigator @InternalVoyagerApi constructor(
179178
) {
180179
ScreenLifecycleStore.remove(screen)
181180
stateKeys
182-
.toMutableSet() // Copy
181+
.toSet() // Copy
182+
.asSequence()
183183
.filter { it.startsWith(screen.key) }
184184
.forEach { key ->
185185
stateHolder.removeState(key)

0 commit comments

Comments
 (0)