ImmutableArrayList and listBuilder() prototype
TODO: lots of improvements, documentation, tests
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
package kotlin
|
||||||
|
|
||||||
|
import java.util.List
|
||||||
|
import java.util.AbstractList
|
||||||
|
|
||||||
|
private class ImmutableArrayList<T>(
|
||||||
|
private val array: Array<T>,
|
||||||
|
private val offset: Int,
|
||||||
|
private val length: Int
|
||||||
|
) : AbstractList<T>() {
|
||||||
|
{
|
||||||
|
// impossible
|
||||||
|
if (offset < 0) {
|
||||||
|
throw IllegalArgumentException("negative offset")
|
||||||
|
}
|
||||||
|
// impossible
|
||||||
|
if (length < 0) {
|
||||||
|
throw IllegalArgumentException("negative length")
|
||||||
|
}
|
||||||
|
// possible when builder is used from different threads
|
||||||
|
if (offset + length > array.size) {
|
||||||
|
throw IllegalArgumentException("offset + length > array.length")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun indexInArray(index: Int): Int {
|
||||||
|
if (index < 0) {
|
||||||
|
throw IllegalArgumentException("negative index")
|
||||||
|
}
|
||||||
|
if (index >= length) {
|
||||||
|
throw IllegalArgumentException("index > length")
|
||||||
|
}
|
||||||
|
return index + offset
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun get(index: Int): T = array[indexInArray(index)] as T
|
||||||
|
|
||||||
|
public override fun size() : Int = length
|
||||||
|
|
||||||
|
public override fun subList(fromIndex: Int, toIndex: Int) : List<T> {
|
||||||
|
if (fromIndex < 0) {
|
||||||
|
throw IllegalArgumentException("negative from index")
|
||||||
|
}
|
||||||
|
if (toIndex < fromIndex) {
|
||||||
|
throw IllegalArgumentException("toIndex < fromIndex")
|
||||||
|
}
|
||||||
|
if (toIndex > length) {
|
||||||
|
throw IllegalArgumentException("fromIndex + toIndex > length")
|
||||||
|
}
|
||||||
|
return ImmutableArrayList(array, offset + fromIndex, toIndex - fromIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: efficiently implement iterator and other stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make val, see http://youtrack.jetbrains.com/issue/KT-2028
|
||||||
|
private fun emptyArray(): Array<Any?> = arrayOfNulls(0)
|
||||||
|
|
||||||
|
public class ImmutableArrayListBuilder<T>() {
|
||||||
|
|
||||||
|
private var array = emptyArray()
|
||||||
|
private var length = 0
|
||||||
|
|
||||||
|
public fun build(): List<T> {
|
||||||
|
val r = ImmutableArrayList<T>(array as Array<T>, 0, length)
|
||||||
|
array = emptyArray()
|
||||||
|
length = 0
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun ensureCapacity(capacity: Int) {
|
||||||
|
if (array.size < capacity) {
|
||||||
|
val newSize = Math.max(capacity, Math.max(array.size * 2, 11))
|
||||||
|
array = array.copyOf(newSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun add(item: T) {
|
||||||
|
ensureCapacity(length + 1)
|
||||||
|
array[length] = item
|
||||||
|
++length
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// default list builder
|
||||||
|
fun <T> listBuilder() = ImmutableArrayListBuilder<T>()
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package test.collection
|
||||||
|
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
import junit.framework.TestCase
|
||||||
|
import java.util.List
|
||||||
|
import java.util.Random
|
||||||
|
|
||||||
|
class ImmutableArrayListTest() : TestCase() {
|
||||||
|
|
||||||
|
fun testSimple() {
|
||||||
|
val builder = ImmutableArrayListBuilder<Int>()
|
||||||
|
builder.add(17)
|
||||||
|
val list = builder.build()
|
||||||
|
assertEquals(1, list.size())
|
||||||
|
assertEquals(17, list[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun testGet() {
|
||||||
|
for (length in 0 .. 55) {
|
||||||
|
val list = buildIntArray(length, 19)
|
||||||
|
assertEquals(length, list.size)
|
||||||
|
checkList(list, length, 19)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildIntArray(length: Int, firstValue: Int): List<Int> {
|
||||||
|
val builder = ImmutableArrayListBuilder<Int>()
|
||||||
|
for (j in 0 .. length - 1) {
|
||||||
|
builder.add(firstValue + j)
|
||||||
|
}
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun checkList(list: List<Int>, expectedLength: Int, expectedFirstValue: Int) {
|
||||||
|
assertEquals(expectedLength, list.size)
|
||||||
|
for (i in 0 .. expectedLength - 1) {
|
||||||
|
assertEquals(expectedFirstValue + i, list[i])
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
list[expectedLength]
|
||||||
|
fail()
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun testSublist() {
|
||||||
|
val r = Random(1)
|
||||||
|
for (i in 0 .. 200) {
|
||||||
|
val length = r.nextInt(55)
|
||||||
|
val list = buildIntArray(length, 23)
|
||||||
|
val fromIndex = r.nextInt(length + 1)
|
||||||
|
val toIndex = fromIndex + r.nextInt(length - fromIndex + 1)
|
||||||
|
val sublist = list.subList(fromIndex, toIndex)
|
||||||
|
checkList(sublist, toIndex - fromIndex, 23 + fromIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user