Skip to content

Commit

Permalink
Merge pull request #326 from arkivanov/optimize-SharedList-for-native
Browse files Browse the repository at this point in the history
Optimized SharedList for Native
  • Loading branch information
Arkadii Ivanov authored Dec 8, 2019
2 parents 7908405 + fb7e751 commit 015f570
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 128 deletions.
Original file line number Diff line number Diff line change
@@ -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<T>(initalList: List<T> = emptyList()) : MutableList<T> {

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<T>): 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<T> = 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<T>): Boolean {
if (elements.isEmpty()) {
return false
}

val oldList = delegate.value
val newList = ArrayList<T>(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<T>): Boolean {
if (elements.isEmpty()) {
return false
}

delegate.value = delegate.value + elements

return true
}

override fun clear() {
delegate.clear()
}

override fun listIterator(): MutableListIterator<T> = MutableListIteratorImpl(this, 0)

override fun listIterator(index: Int): MutableListIterator<T> = MutableListIteratorImpl(this, index)

override fun remove(element: T): Boolean = delegate.remove(element)

override fun removeAll(elements: Collection<T>): 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<T>): 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<T> {
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<T>(
private val list: MutableList<T>,
private var index: Int
) : MutableListIterator<T> {
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
}
}
}
Original file line number Diff line number Diff line change
@@ -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<T> actual constructor(initialCapacity: Int) : MutableList<T> {

private val delegate = AtomicList<T>(emptyList())
private val helper =
MutableFreezableHelper<MutableList<T>, ArrayList<T>, CopyOnWriteList<T>>(
mutableFactory = { ArrayList(initialCapacity) },
freezableFactory = { CopyOnWriteList(it ?: emptyList()) }
)

private val delegate: MutableList<T> 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<T>): Boolean = delegate.value.containsAll(elements)
override fun containsAll(elements: Collection<T>): 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<T> = MutableListIteratorImpl(this, 0)
override fun iterator(): MutableIterator<T> = 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<T>): Boolean {
if (elements.isEmpty()) {
return false
}

val oldList = delegate.value
val newList = ArrayList<T>(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<T>): Boolean {
if (elements.isEmpty()) {
return false
}
override fun addAll(index: Int, elements: Collection<T>): Boolean = delegate.addAll(index, elements)

delegate.value = delegate.value + elements

return true
}
override fun addAll(elements: Collection<T>): Boolean = delegate.addAll(elements)

override fun clear() {
delegate.clear()
}

override fun listIterator(): MutableListIterator<T> = MutableListIteratorImpl(this, 0)
override fun listIterator(): MutableListIterator<T> = delegate.listIterator()

override fun listIterator(index: Int): MutableListIterator<T> = MutableListIteratorImpl(this, index)
override fun listIterator(index: Int): MutableListIterator<T> = delegate.listIterator(index)

override fun remove(element: T): Boolean = delegate.remove(element)

override fun removeAll(elements: Collection<T>): Boolean {
val oldList = delegate.value
val newList = oldList - elements
delegate.value = newList

return newList.size < oldList.size
}
override fun removeAll(elements: Collection<T>): Boolean = delegate.removeAll(elements)

override fun removeAt(index: Int): T = delegate.removeAt(index)

override fun retainAll(elements: Collection<T>): Boolean {
val oldList = delegate.value
val newList = oldList.filter(elements::contains)
delegate.value = newList

return newList.size < oldList.size
}
override fun retainAll(elements: Collection<T>): Boolean = delegate.retainAll(elements)

override fun set(index: Int, element: T): T = delegate.set(index, element)

override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> {
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<T>(
private val list: MutableList<T>,
private var index: Int
) : MutableListIterator<T> {
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()
}
Original file line number Diff line number Diff line change
@@ -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<Int?>, MutableList<Int?>> = Pair(SharedList(), ArrayList())
val lists: Pair<MutableList<Int?>, MutableList<Int?>> = Pair(CopyOnWriteList<Int?>().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())
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Int?> = SharedList()
private val list = CopyOnWriteList<Int?>().freeze()

@Test
fun contains() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String?>().freeze())

0 comments on commit 015f570

Please sign in to comment.