diff --git a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/model/ScreenModelStore.kt b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/model/ScreenModelStore.kt index dbfa037b..71be822f 100644 --- a/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/model/ScreenModelStore.kt +++ b/voyager-core/src/commonMain/kotlin/cafe/adriel/voyager/core/model/ScreenModelStore.kt @@ -114,6 +114,7 @@ public object ScreenModelStore : ScreenDisposable { private fun Map.onEachHolder(holderKey: String, block: (String) -> Unit) = toMap() // copy + .asSequence() .filter { it.key.startsWith(holderKey) } .map { it.key } .forEach(block) diff --git a/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.native.kt b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.native.kt index 591c2f2d..3edc0dd6 100644 --- a/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.native.kt +++ b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.native.kt @@ -3,22 +3,12 @@ package cafe.adriel.voyager.core.concurrent import kotlinx.atomicfu.locks.SynchronizedObject import kotlinx.atomicfu.locks.synchronized -public actual class ThreadSafeList( +public actual class ThreadSafeList internal constructor( + private val syncObject: SynchronizedObject, private val delegate: MutableList -) : MutableList { +) : MutableList, ThreadSafeMutableCollection(syncObject, delegate) { public actual constructor() : this(delegate = mutableListOf()) - private val syncObject = SynchronizedObject() - - override val size: Int - get() = delegate.size - - override fun contains(element: T): Boolean { - return synchronized(syncObject) { delegate.contains(element) } - } - - override fun containsAll(elements: Collection): Boolean { - return synchronized(syncObject) { delegate.containsAll(elements) } - } + public constructor(delegate: MutableList) : this(SynchronizedObject(), delegate) override fun get(index: Int): T { return synchronized(syncObject) { delegate.get(index) } @@ -28,22 +18,10 @@ public actual class ThreadSafeList( return synchronized(syncObject) { delegate.indexOf(element) } } - override fun isEmpty(): Boolean { - return synchronized(syncObject) { delegate.isEmpty() } - } - - override fun iterator(): MutableIterator { - return synchronized(syncObject) { delegate.iterator() } - } - override fun lastIndexOf(element: T): Int { return synchronized(syncObject) { delegate.lastIndexOf(element) } } - override fun add(element: T): Boolean { - return synchronized(syncObject) { delegate.add(element) } - } - override fun add(index: Int, element: T) { return synchronized(syncObject) { delegate.add(index, element) } } @@ -52,43 +30,23 @@ public actual class ThreadSafeList( return synchronized(syncObject) { delegate.addAll(index, elements) } } - override fun addAll(elements: Collection): Boolean { - return synchronized(syncObject) { delegate.addAll(elements) } - } - - override fun clear() { - return synchronized(syncObject) { delegate.clear() } - } - override fun listIterator(): MutableListIterator { - return synchronized(syncObject) { delegate.listIterator() } + return synchronized(syncObject) { ThreadSafeMutableListIterator(syncObject, delegate.listIterator()) } } override fun listIterator(index: Int): MutableListIterator { - return synchronized(syncObject) { delegate.listIterator(index) } - } - - override fun remove(element: T): Boolean { - return synchronized(syncObject) { delegate.remove(element) } - } - - override fun removeAll(elements: Collection): Boolean { - return synchronized(syncObject) { delegate.removeAll(elements) } + return synchronized(syncObject) { ThreadSafeMutableListIterator(syncObject, delegate.listIterator(index)) } } override fun removeAt(index: Int): T { return synchronized(syncObject) { delegate.removeAt(index) } } - override fun retainAll(elements: Collection): Boolean { - return synchronized(syncObject) { delegate.retainAll(elements) } - } - override fun set(index: Int, element: T): T { return synchronized(syncObject) { delegate.set(index, element) } } override fun subList(fromIndex: Int, toIndex: Int): MutableList { - return synchronized(syncObject) { delegate.subList(fromIndex, toIndex) } + return synchronized(syncObject) { ThreadSafeList(syncObject, delegate.subList(fromIndex, toIndex)) } } } diff --git a/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.native.kt b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.native.kt index 10a13c83..ac674afe 100644 --- a/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.native.kt +++ b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.native.kt @@ -29,11 +29,11 @@ public actual class ThreadSafeMap( } override val entries: MutableSet> - get() = synchronized(syncObject) { delegate.entries.toMutableSet() } + get() = synchronized(syncObject) { ThreadSafeSet(syncObject, delegate.entries) } override val keys: MutableSet - get() = synchronized(syncObject) { delegate.keys.toMutableSet() } + get() = synchronized(syncObject) { ThreadSafeSet(syncObject, delegate.keys) } override val values: MutableCollection - get() = synchronized(syncObject) { delegate.values.toMutableList() } + get() = synchronized(syncObject) { ThreadSafeMutableCollection(syncObject, delegate.values) } override fun clear() { synchronized(syncObject) { delegate.clear() } diff --git a/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMutableCollection.kt b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMutableCollection.kt new file mode 100644 index 00000000..7be8208e --- /dev/null +++ b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMutableCollection.kt @@ -0,0 +1,53 @@ +package cafe.adriel.voyager.core.concurrent + +import kotlinx.atomicfu.locks.SynchronizedObject +import kotlinx.atomicfu.locks.synchronized + +public open class ThreadSafeMutableCollectioninternal constructor( + private val syncObject: SynchronizedObject, + private val delegate: MutableCollection +) : MutableCollection { + + override val size: Int + get() = synchronized(syncObject) { delegate.size } + + override fun contains(element: T): Boolean { + return synchronized(syncObject) { delegate.contains(element) } + } + + override fun containsAll(elements: Collection): Boolean { + return synchronized(syncObject) { delegate.containsAll(elements) } + } + + override fun isEmpty(): Boolean { + return synchronized(syncObject) { delegate.isEmpty() } + } + + override fun iterator(): MutableIterator { + return synchronized(syncObject) { ThreadSafeMutableIterator(syncObject, delegate.iterator()) } + } + + override fun add(element: T): Boolean { + return synchronized(syncObject) { delegate.add(element) } + } + + override fun addAll(elements: Collection): Boolean { + return synchronized(syncObject) { delegate.addAll(elements) } + } + + override fun clear() { + return synchronized(syncObject) { delegate.clear() } + } + + override fun remove(element: T): Boolean { + return synchronized(syncObject) { delegate.remove(element) } + } + + override fun removeAll(elements: Collection): Boolean { + return synchronized(syncObject) { delegate.removeAll(elements) } + } + + override fun retainAll(elements: Collection): Boolean { + return synchronized(syncObject) { delegate.retainAll(elements) } + } +} diff --git a/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMutableIterator.kt b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMutableIterator.kt new file mode 100644 index 00000000..af69c366 --- /dev/null +++ b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMutableIterator.kt @@ -0,0 +1,40 @@ +package cafe.adriel.voyager.core.concurrent + +import kotlinx.atomicfu.locks.SynchronizedObject +import kotlinx.atomicfu.locks.synchronized + +internal open class ThreadSafeMutableIterator( + private val syncObject: SynchronizedObject, + private val delegate: MutableIterator +) : MutableIterator { + override fun hasNext(): Boolean = synchronized(syncObject) { delegate.hasNext() } + + override fun next(): E = synchronized(syncObject) { delegate.next() } + + override fun remove() { + synchronized(syncObject) { delegate.remove() } + } +} + +internal class ThreadSafeMutableListIterator( + private val syncObject: SynchronizedObject, + private val delegate: MutableListIterator +) : ThreadSafeMutableIterator(syncObject, delegate), + MutableListIterator { + + override fun hasPrevious(): Boolean = synchronized(syncObject) { delegate.hasPrevious() } + + override fun nextIndex(): Int = synchronized(syncObject) { delegate.nextIndex() } + + override fun previous(): E = synchronized(syncObject) { delegate.previous() } + + override fun previousIndex(): Int = synchronized(syncObject) { delegate.previousIndex() } + + override fun add(element: E) { + synchronized(syncObject) { delegate.add(element) } + } + + override fun set(element: E) { + synchronized(syncObject) { delegate.set(element) } + } +} diff --git a/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.native.kt b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.native.kt index c3139ca2..641c7b7c 100644 --- a/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.native.kt +++ b/voyager-core/src/nativeMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.native.kt @@ -4,51 +4,9 @@ import kotlinx.atomicfu.locks.SynchronizedObject import kotlinx.atomicfu.locks.synchronized public actual class ThreadSafeSet( - private val delegate: MutableSet -) : MutableSet { + syncObject: SynchronizedObject, + delegate: MutableSet +) : MutableSet, ThreadSafeMutableCollection(syncObject, delegate) { public actual constructor() : this(delegate = mutableSetOf()) - private val syncObject = SynchronizedObject() - - override val size: Int - get() = delegate.size - - override fun contains(element: T): Boolean { - return synchronized(syncObject) { delegate.contains(element) } - } - - override fun containsAll(elements: Collection): Boolean { - return synchronized(syncObject) { delegate.containsAll(elements) } - } - - override fun isEmpty(): Boolean { - return synchronized(syncObject) { delegate.isEmpty() } - } - - override fun iterator(): MutableIterator { - return synchronized(syncObject) { delegate.iterator() } - } - - override fun add(element: T): Boolean { - return synchronized(syncObject) { delegate.add(element) } - } - - override fun addAll(elements: Collection): Boolean { - return synchronized(syncObject) { delegate.addAll(elements) } - } - - override fun clear() { - return synchronized(syncObject) { delegate.clear() } - } - - override fun remove(element: T): Boolean { - return synchronized(syncObject) { delegate.remove(element) } - } - - override fun removeAll(elements: Collection): Boolean { - return synchronized(syncObject) { delegate.removeAll(elements) } - } - - override fun retainAll(elements: Collection): Boolean { - return synchronized(syncObject) { delegate.retainAll(elements) } - } + public constructor(delegate: MutableSet) : this(SynchronizedObject(), delegate) } diff --git a/voyager-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/Navigator.kt b/voyager-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/Navigator.kt index 94cef193..a4a7ff4f 100644 --- a/voyager-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/Navigator.kt +++ b/voyager-navigator/src/commonMain/kotlin/cafe/adriel/voyager/navigator/Navigator.kt @@ -17,7 +17,6 @@ import cafe.adriel.voyager.core.lifecycle.MultipleProvideBeforeScreenContent import cafe.adriel.voyager.core.lifecycle.ScreenLifecycleStore import cafe.adriel.voyager.core.lifecycle.getNavigatorScreenLifecycleProvider import cafe.adriel.voyager.core.lifecycle.rememberScreenLifecycleOwner -import cafe.adriel.voyager.core.model.ScreenModelStore import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.stack.Stack import cafe.adriel.voyager.core.stack.toMutableStateStack @@ -179,7 +178,8 @@ public class Navigator @InternalVoyagerApi constructor( ) { ScreenLifecycleStore.remove(screen) stateKeys - .toMutableSet() // Copy + .toSet() // Copy + .asSequence() .filter { it.startsWith(screen.key) } .forEach { key -> stateHolder.removeState(key)