diff --git a/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/CopyOnWriteList.kt b/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/CopyOnWriteList.kt new file mode 100644 index 000000000..d5c93e51c --- /dev/null +++ b/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/CopyOnWriteList.kt @@ -0,0 +1,164 @@ +package com.badoo.reaktive.utils + +import com.badoo.reaktive.utils.atomic.AtomicList +import com.badoo.reaktive.utils.atomic.add +import com.badoo.reaktive.utils.atomic.clear +import com.badoo.reaktive.utils.atomic.get +import com.badoo.reaktive.utils.atomic.isEmpty +import com.badoo.reaktive.utils.atomic.plusAssign +import com.badoo.reaktive.utils.atomic.remove +import com.badoo.reaktive.utils.atomic.removeAt +import com.badoo.reaktive.utils.atomic.set +import com.badoo.reaktive.utils.atomic.size + +internal class CopyOnWriteList(initalList: List = emptyList()) : MutableList { + + private val delegate = AtomicList(initalList) + + override val size: Int get() = delegate.size + + override fun contains(element: T): Boolean = delegate.value.contains(element) + + override fun containsAll(elements: Collection): Boolean = delegate.value.containsAll(elements) + + override fun get(index: Int): T = delegate[index] + + override fun indexOf(element: T): Int = delegate.value.indexOf(element) + + override fun isEmpty(): Boolean = delegate.isEmpty + + override fun iterator(): MutableIterator = MutableListIteratorImpl(this, 0) + + override fun lastIndexOf(element: T): Int = delegate.value.lastIndexOf(element) + + override fun add(element: T): Boolean { + delegate += element + + return true + } + + override fun add(index: Int, element: T) { + delegate.add(index, element) + } + + override fun addAll(index: Int, elements: Collection): Boolean { + if (elements.isEmpty()) { + return false + } + + val oldList = delegate.value + val newList = ArrayList(oldList.size + elements.size) + + for (i in 0 until index) { + newList.add(oldList[i]) + } + + newList.addAll(elements) + + for (i in index until oldList.size) { + newList.add(oldList[i]) + } + + delegate.value = newList + + return true + } + + override fun addAll(elements: Collection): Boolean { + if (elements.isEmpty()) { + return false + } + + delegate.value = delegate.value + elements + + return true + } + + override fun clear() { + delegate.clear() + } + + override fun listIterator(): MutableListIterator = MutableListIteratorImpl(this, 0) + + override fun listIterator(index: Int): MutableListIterator = MutableListIteratorImpl(this, index) + + override fun remove(element: T): Boolean = delegate.remove(element) + + override fun removeAll(elements: Collection): Boolean { + val oldList = delegate.value + val newList = oldList - elements + delegate.value = newList + + return newList.size < oldList.size + } + + override fun removeAt(index: Int): T = delegate.removeAt(index) + + override fun retainAll(elements: Collection): Boolean { + val oldList = delegate.value + val newList = oldList.filter(elements::contains) + delegate.value = newList + + return newList.size < oldList.size + } + + override fun set(index: Int, element: T): T = delegate.set(index, element) + + override fun subList(fromIndex: Int, toIndex: Int): MutableList { + throw NotImplementedError() // It's tricky and we don't need it at the moment + } + + override fun equals(other: Any?): Boolean = delegate.value == other + + override fun hashCode(): Int = delegate.value.hashCode() + + private inner class MutableListIteratorImpl( + private val list: MutableList, + private var index: Int + ) : MutableListIterator { + private var lastIndex = -1 + + override fun hasPrevious(): Boolean = index > 0 + override fun hasNext(): Boolean = index < list.size + + override fun previousIndex(): Int = index - 1 + override fun nextIndex(): Int = index + + override fun previous(): T { + if (index <= 0) { + throw NoSuchElementException() + } + + lastIndex = --index + + return list[lastIndex] + } + + override fun next(): T { + if (index >= list.size) { + throw NoSuchElementException() + } + + lastIndex = index++ + + return list[lastIndex] + } + + override fun set(element: T) { + list[lastIndex] = element + } + + override fun add(element: T) { + list.add(index++, element) + lastIndex = -1 + } + + override fun remove() { + check(lastIndex != -1) { "Call next() or previous() before removing element from the iterator." } + + list.removeAt(lastIndex) + index = lastIndex + lastIndex = -1 + } + } +} diff --git a/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/SharedList.kt b/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/SharedList.kt index beebc1e0f..bab8dd80d 100644 --- a/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/SharedList.kt +++ b/reaktive/src/nativeCommonMain/kotlin/com/badoo/reaktive/utils/SharedList.kt @@ -1,164 +1,64 @@ package com.badoo.reaktive.utils -import com.badoo.reaktive.utils.atomic.AtomicList -import com.badoo.reaktive.utils.atomic.add -import com.badoo.reaktive.utils.atomic.clear -import com.badoo.reaktive.utils.atomic.get -import com.badoo.reaktive.utils.atomic.isEmpty -import com.badoo.reaktive.utils.atomic.plusAssign -import com.badoo.reaktive.utils.atomic.remove -import com.badoo.reaktive.utils.atomic.removeAt -import com.badoo.reaktive.utils.atomic.set -import com.badoo.reaktive.utils.atomic.size - internal actual class SharedList actual constructor(initialCapacity: Int) : MutableList { - private val delegate = AtomicList(emptyList()) + private val helper = + MutableFreezableHelper, ArrayList, CopyOnWriteList>( + mutableFactory = { ArrayList(initialCapacity) }, + freezableFactory = { CopyOnWriteList(it ?: emptyList()) } + ) + + private val delegate: MutableList get() = helper.obj override val size: Int get() = delegate.size - override fun contains(element: T): Boolean = delegate.value.contains(element) + override fun contains(element: T): Boolean = delegate.contains(element) - override fun containsAll(elements: Collection): Boolean = delegate.value.containsAll(elements) + override fun containsAll(elements: Collection): Boolean = delegate.containsAll(elements) override fun get(index: Int): T = delegate[index] - override fun indexOf(element: T): Int = delegate.value.indexOf(element) + override fun indexOf(element: T): Int = delegate.indexOf(element) - override fun isEmpty(): Boolean = delegate.isEmpty + override fun isEmpty(): Boolean = delegate.isEmpty() - override fun iterator(): MutableIterator = MutableListIteratorImpl(this, 0) + override fun iterator(): MutableIterator = delegate.iterator() - override fun lastIndexOf(element: T): Int = delegate.value.lastIndexOf(element) + override fun lastIndexOf(element: T): Int = delegate.lastIndexOf(element) - override fun add(element: T): Boolean { - delegate += element - - return true - } + override fun add(element: T): Boolean = delegate.add(element) override fun add(index: Int, element: T) { delegate.add(index, element) } - override fun addAll(index: Int, elements: Collection): Boolean { - if (elements.isEmpty()) { - return false - } - - val oldList = delegate.value - val newList = ArrayList(oldList.size + elements.size) - - for (i in 0 until index) { - newList.add(oldList[i]) - } - - newList.addAll(elements) - - for (i in index until oldList.size) { - newList.add(oldList[i]) - } - - delegate.value = newList - - return true - } - - override fun addAll(elements: Collection): Boolean { - if (elements.isEmpty()) { - return false - } + override fun addAll(index: Int, elements: Collection): Boolean = delegate.addAll(index, elements) - delegate.value = delegate.value + elements - - return true - } + override fun addAll(elements: Collection): Boolean = delegate.addAll(elements) override fun clear() { delegate.clear() } - override fun listIterator(): MutableListIterator = MutableListIteratorImpl(this, 0) + override fun listIterator(): MutableListIterator = delegate.listIterator() - override fun listIterator(index: Int): MutableListIterator = MutableListIteratorImpl(this, index) + override fun listIterator(index: Int): MutableListIterator = delegate.listIterator(index) override fun remove(element: T): Boolean = delegate.remove(element) - override fun removeAll(elements: Collection): Boolean { - val oldList = delegate.value - val newList = oldList - elements - delegate.value = newList - - return newList.size < oldList.size - } + override fun removeAll(elements: Collection): Boolean = delegate.removeAll(elements) override fun removeAt(index: Int): T = delegate.removeAt(index) - override fun retainAll(elements: Collection): Boolean { - val oldList = delegate.value - val newList = oldList.filter(elements::contains) - delegate.value = newList - - return newList.size < oldList.size - } + override fun retainAll(elements: Collection): Boolean = delegate.retainAll(elements) override fun set(index: Int, element: T): T = delegate.set(index, element) override fun subList(fromIndex: Int, toIndex: Int): MutableList { - throw NotImplementedError() // It's tricky and we need it at the moment + throw NotImplementedError() // It's tricky and we don't need it at the moment } - override fun equals(other: Any?): Boolean = delegate.value == other - - override fun hashCode(): Int = delegate.value.hashCode() - - private inner class MutableListIteratorImpl( - private val list: MutableList, - private var index: Int - ) : MutableListIterator { - private var lastIndex = -1 - - override fun hasPrevious(): Boolean = index > 0 - override fun hasNext(): Boolean = index < list.size - - override fun previousIndex(): Int = index - 1 - override fun nextIndex(): Int = index - - override fun previous(): T { - if (index <= 0) { - throw NoSuchElementException() - } - - lastIndex = --index + override fun equals(other: Any?): Boolean = delegate == other - return list[lastIndex] - } - - override fun next(): T { - if (index >= list.size) { - throw NoSuchElementException() - } - - lastIndex = index++ - - return list[lastIndex] - } - - override fun set(element: T) { - list[lastIndex] = element - } - - override fun add(element: T) { - list.add(index++, element) - lastIndex = -1 - } - - override fun remove() { - check(lastIndex != -1) { "Call next() or previous() before removing element from the iterator." } - - list.removeAt(lastIndex) - index = lastIndex - lastIndex = -1 - } - } + override fun hashCode(): Int = delegate.hashCode() } diff --git a/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/SharedListIteratorTest.kt b/reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/CopyOnWriteListIteratorTest.kt similarity index 95% rename from reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/SharedListIteratorTest.kt rename to reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/CopyOnWriteListIteratorTest.kt index 7d5d11fd5..7ddff1682 100644 --- a/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/SharedListIteratorTest.kt +++ b/reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/CopyOnWriteListIteratorTest.kt @@ -1,13 +1,14 @@ package com.badoo.reaktive.utils +import kotlin.native.concurrent.freeze import kotlin.test.Test import kotlin.test.assertEquals -class SharedListIteratorTest { +class CopyOnWriteListIteratorTest { @Test fun listIterator() { - val lists: Pair, MutableList> = Pair(SharedList(), ArrayList()) + val lists: Pair, MutableList> = Pair(CopyOnWriteList().freeze(), ArrayList()) lists.first.addAll(listOf(0, null, 1, null, 2)) lists.second.addAll(listOf(0, null, 1, null, 2)) val iterators = Pair(lists.first.listIterator(), lists.second.listIterator()) diff --git a/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/SharedListTest.kt b/reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/CopyOnWriteListTest.kt similarity index 96% rename from reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/SharedListTest.kt rename to reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/CopyOnWriteListTest.kt index f787134f7..9593ca94e 100644 --- a/reaktive/src/commonTest/kotlin/com/badoo/reaktive/utils/SharedListTest.kt +++ b/reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/CopyOnWriteListTest.kt @@ -1,14 +1,15 @@ package com.badoo.reaktive.utils +import kotlin.native.concurrent.freeze import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse import kotlin.test.assertTrue -class SharedListTest { +class CopyOnWriteListTest { - private val list: MutableList = SharedList() + private val list = CopyOnWriteList().freeze() @Test fun contains() { diff --git a/reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/queue/CopyOnWriteQueueTest.kt b/reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/queue/CopyOnWriteQueueTest.kt index 080c09a3e..60328fdb9 100644 --- a/reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/queue/CopyOnWriteQueueTest.kt +++ b/reaktive/src/nativeCommonTest/kotlin/com/badoo/reaktive/utils/queue/CopyOnWriteQueueTest.kt @@ -1,5 +1,5 @@ package com.badoo.reaktive.utils.queue -import com.badoo.reaktive.utils.freeze +import kotlin.native.concurrent.freeze class CopyOnWriteQueueTest : QueueTests by QueueTestsImpl(CopyOnWriteQueue().freeze())