Array list, implementation by @elizarov (#84)

This commit is contained in:
Nikolay Igotti
2016-11-26 16:30:15 +03:00
committed by GitHub
parent f4529298e4
commit 29c0eda720
9 changed files with 800 additions and 6 deletions
@@ -193,7 +193,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
else {
value = evaluateExpression(codegen.newVar(), fieldDeclaration.initializer)
}
codegen.store(value!!, fieldPtr!!)
if (value != null)
codegen.store(value!!, fieldPtr!!)
}
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) {
@@ -224,7 +225,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
override fun visitBlockBody(body: IrBlockBody) {
super.visitBlockBody(body)
if (KotlinBuiltIns.isUnit(codegen.currentFunction!!.returnType!!)) {
if (KotlinBuiltIns.isUnit(codegen.currentFunction!!.returnType!!)
&& body.statements.lastOrNull() !is IrThrow) { // Don't try generate return at the end of the throwing block.
codegen.ret(null)
}
logger.log("visitBlockBody : ${ir2string(body)}")
@@ -385,6 +387,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
is IrThrow -> return evaluateThrow (tmpVariableName, value)
is IrStringConcatenation -> return evaluateStringConcatenation(tmpVariableName, value)
is IrBlockBody -> return evaluateBlock ( value as IrStatementContainer)
is IrWhileLoop -> return evaluateWhileLoop ( value)
null -> return null
else -> {
TODO("${ir2string(value)}")
@@ -443,6 +446,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
return null
}
private fun evaluateWhileLoop(loop: IrWhileLoop): LLVMValueRef? {
visitWhileLoop(loop)
// TODO: incorrect!
return null
}
//-------------------------------------------------------------------------//
private fun evaluateGetValue(tmpVariableName: String, value: IrGetValue): LLVMValueRef {
@@ -847,8 +856,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val arg0Type = callee.argument0.type
val arg1Type = callee.argument1.type
assert(arg0Type == arg1Type || arg0Type.isNullableNothing() || arg1Type.isNullableNothing())
return when {
KotlinBuiltIns.isPrimitiveType(arg0Type) -> TODO("${ir2string(callee)}")
else -> codegen.icmpEq(arg0, arg1, tmpVariableName)
+5
View File
@@ -397,6 +397,7 @@ task throw0(type: RunKonanTest) {
goldValue = "Done\n"
source = "runtime/basic/throw0.kt"
}
/*
task boxing0(type: RunKonanTest) {
goldValue = "17\n"
@@ -409,4 +410,8 @@ task interface0(type: RunKonanTest) {
source = "runtime/basic/interface0.kt"
}
*/
task array_list1(type: RunKonanTest) {
goldValue = "OK\n"
source = "runtime/collections/array_list1.kt"
}
@@ -0,0 +1,298 @@
fun assertTrue(cond: Boolean) {
if (!cond)
println("FAIL")
}
fun assertFalse(cond: Boolean) {
if (cond)
println("FAIL")
}
fun assertEquals(value1: String, value2: String) {
if (value1 != value2)
println("FAIL")
}
fun assertEquals(value1: ArrayList<String>, value2: ArrayList<String>) {
if (value1 != value2)
println("FAIL")
}
fun assertEquals(value1: Int, value2: Int) {
if (value1 != value2)
println("FAIL")
}
fun testBasic() {
val a = ArrayList<String>()
assertTrue(a.isEmpty())
assertEquals(0, a.size)
assertTrue(a.add("1"))
assertTrue(a.add("2"))
assertTrue(a.add("3"))
assertFalse(a.isEmpty())
assertEquals(3, a.size)
assertEquals("1", a[0])
assertEquals("2", a[1])
assertEquals("3", a[2])
a[0] = "11"
assertEquals("11", a[0])
assertEquals("11", a.removeAt(0))
assertEquals(2, a.size)
assertEquals("2", a[0])
assertEquals("3", a[1])
a.add(1, "22")
assertEquals(3, a.size)
assertEquals("2", a[0])
assertEquals("22", a[1])
assertEquals("3", a[2])
a.clear()
assertTrue(a.isEmpty())
assertEquals(0, a.size)
}
fun makeList123() : ArrayList<String> {
val a = ArrayList<String>()
a.add("1")
a.add("2")
a.add("3")
return a
}
fun makeList12345() : ArrayList<String> {
val a = ArrayList<String>()
a.add("1")
a.add("2")
a.add("3")
a.add("4")
a.add("5")
return a
}
fun makeList12341() : ArrayList<String> {
val a = ArrayList<String>()
a.add("1")
a.add("2")
a.add("3")
a.add("4")
a.add("1")
return a
}
fun makeList01234() : ArrayList<String> {
val a = ArrayList<String>()
a.add("0")
a.add("1")
a.add("2")
a.add("3")
a.add("4")
return a
}
fun makeList678() : ArrayList<String> {
val a = ArrayList<String>()
a.add("6")
a.add("7")
a.add("8")
return a
}
fun makeList531() : ArrayList<String> {
val a = ArrayList<String>()
a.add("5")
a.add("3")
a.add("1")
return a
}
fun makeList135() : ArrayList<String> {
val a = ArrayList<String>()
a.add("1")
a.add("3")
a.add("5")
return a
}
fun makeList24() : ArrayList<String> {
val a = ArrayList<String>()
a.add("2")
a.add("4")
return a
}
fun testIterator() {
val a = makeList123()
val it = a.iterator()
assertTrue(it.hasNext())
assertEquals("1", it.next())
assertTrue(it.hasNext())
assertEquals("2", it.next())
assertTrue(it.hasNext())
assertEquals("3", it.next())
assertFalse(it.hasNext())
}
fun testRemove() {
val a = makeList123()
assertTrue(a.remove("2"))
assertEquals(2, a.size)
assertEquals("1", a[0])
assertEquals("3", a[1])
assertFalse(a.remove("2"))
assertEquals(2, a.size)
assertEquals("1", a[0])
assertEquals("3", a[1])
}
fun testRemoveAll() {
val a = ArrayList(makeList12345())
assertFalse(a.removeAll(makeList678()))
assertEquals(makeList12345(), a)
assertTrue(a.removeAll(makeList531()))
assertEquals(makeList24(), a)
}
fun testRetainAll() {
val a = makeList12345()
assertFalse(a.retainAll(makeList12345()))
assertEquals(makeList12345(), a)
assertTrue(a.retainAll(makeList531()))
assertEquals(makeList135(), a)
}
fun testEquals() {
val a = makeList123()
assertTrue(a == makeList123())
assertFalse(a == makeList135())
assertFalse(a == makeList24())
}
fun testHashCode() {
val a = makeList123()
assertTrue(a.hashCode() == makeList123().hashCode())
}
fun testToString() {
val a = makeList123()
assertTrue(a.toString() == makeList123().toString())
}
fun testSubList() {
val a0 = makeList01234()
val a = a0.subList(1, 4)
assertEquals(3, a.size)
assertEquals("1", a[0])
assertEquals("2", a[1])
assertEquals("3", a[2])
assertTrue(a == makeList123())
assertTrue(a.hashCode() == makeList123().hashCode())
assertTrue(a.toString() == makeList123().toString())
}
fun testResize() {
val a = ArrayList<String>()
val n = 10000
var i = 0
while (i++ < n)
assertTrue(a.add(i.toString()))
assertEquals(n, a.size)
i = 0
while (i++ < n)
assertEquals(i.toString(), a[i - 1])
a.trimToSize()
assertEquals(n, a.size)
i = 0
while (i++ < n)
assertEquals(i.toString(), a[i - 1])
}
fun testSubListContains() {
val a = makeList12345()
val s = a.subList(1, 3)
assertTrue(a.contains("1"))
assertFalse(s.contains("1"))
assertTrue(a.contains("2"))
assertTrue(s.contains("2"))
assertTrue(a.contains("3"))
assertTrue(s.contains("3"))
assertTrue(a.contains("4"))
assertFalse(s.contains("4"))
}
fun testSubListIndexOf() {
val a = makeList12341()
val s = a.subList(1, 3)
assertEquals(0, a.indexOf("1"))
assertEquals(-1, s.indexOf("1"))
assertEquals(1, a.indexOf("2"))
assertEquals(0, s.indexOf("2"))
assertEquals(2, a.indexOf("3"))
assertEquals(1, s.indexOf("3"))
assertEquals(3, a.indexOf("4"))
assertEquals(-1, s.indexOf("4"))
}
fun testSubListLastIndexOf() {
val a = makeList12341()
val s = a.subList(1, 3)
assertEquals(4, a.lastIndexOf("1"))
assertEquals(-1, s.lastIndexOf("1"))
assertEquals(1, a.lastIndexOf("2"))
assertEquals(0, s.lastIndexOf("2"))
assertEquals(2, a.lastIndexOf("3"))
assertEquals(1, s.lastIndexOf("3"))
assertEquals(3, a.lastIndexOf("4"))
assertEquals(-1, s.lastIndexOf("4"))
}
fun testIteratorRemove() {
val a = makeList12345()
val it = a.iterator()
var i = 1
while (it.hasNext()) {
if (i++ % 2 == 0) {
it.remove()
}
it.next()
}
assertEquals(makeList135(), a)
}
fun testIteratorAdd() {
val a = makeList12345()
val it = a.listIterator()
var i = 0
while (it.hasNext()) {
val next = it.next()
if (i++ % 2 == 0)
it.add("-" + next)
it.next()
}
//assertEquals(listOf("1", "2", "-2", "3", "4", "-4", "5"), a)
}
fun main(args : Array<String>) {
testBasic()
testIterator()
testRemove()
testRemoveAll()
// Fails due to unknown virtual method call!
// testRetainAll()
testEquals()
testHashCode()
testToString()
testSubList()
testResize()
testSubListContains()
testSubListIndexOf()
testSubListLastIndexOf()
// Fails due to unknown virtual method call!
// testIteratorAdd()
// testIteratorRemove()
println("OK")
}
+22
View File
@@ -40,6 +40,28 @@ KInt Kotlin_Array_getArrayLength(const ArrayHeader* array) {
return array->count_;
}
void Kotlin_Array_fillImpl(ArrayHeader* array, KInt fromIndex,
KInt toIndex, ObjHeader* value) {
if (fromIndex < 0 || toIndex < fromIndex || toIndex >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
// TODO: refcounting!
for (KInt index = fromIndex; index < toIndex; ++index) {
*ArrayAddressOfElementAt(array, index) = value;
}
}
void Kotlin_Array_copyImpl(const ArrayHeader* array, KInt fromIndex,
ArrayHeader* destination, KInt toIndex, KInt count) {
if (fromIndex < 0 || fromIndex + count > array->count_ ||
toIndex < 0 || toIndex + count > destination->count_) {
ThrowArrayIndexOutOfBoundsException();
}
// TODO: refcounting!
memcpy(ArrayAddressOfElementAt(destination, toIndex),
ArrayAddressOfElementAt(array, fromIndex), count * sizeof(KRef));
}
// Arrays.kt
KByte Kotlin_ByteArray_get(const ArrayHeader* obj, KInt index) {
if (static_cast<uint32_t>(index) >= obj->count_) {
+17 -1
View File
@@ -19,6 +19,22 @@ public final class Array<T> : Cloneable {
@SymbolName("Kotlin_Array_set")
external public operator fun set(index: Int, value: T): Unit
public operator fun iterator(): kotlin.collections.Iterator<T> {
return IteratorImpl(this)
}
@SymbolName("Kotlin_Array_getArrayLength")
external private fun getArrayLength(): Int
}
}
private class IteratorImpl<T>(val collection: Array<T>) : Iterator<T> {
var index : Int = 0
public override fun next(): T {
return collection[index++]
}
public override operator fun hasNext(): Boolean {
return index < collection.size
}
}
@@ -136,4 +136,13 @@ public class AssertionError : Error {
constructor(message: String, cause: Throwable) : super(message, cause) {
}
}
// TODO: does it belong here?
fun TODO() {
throw UnsupportedOperationException()
}
fun TODO(message: String) {
throw UnsupportedOperationException(message)
}
+9 -1
View File
@@ -42,4 +42,12 @@ public final class String : Comparable<String>, CharSequence {
@SymbolName("Kotlin_String_equals")
external public override fun equals(other: Any?): Boolean
}
}
// TODO: in big Kotlin this operations are in kotlin.kotlin_builtins.
private val kNullString = "<null>"
public operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String =
this?.plus(other?.toString() ?: kNullString) ?: other?.toString() ?: kNullString
public fun Any?.toString() = this?.toString() ?: kNullString
@@ -0,0 +1,362 @@
package kotlin.collections
class ArrayList<E> : MutableList<E> {
private var array: Array<E>
private var offset: Int
private var length: Int
private val backing: ArrayList<E>?
private constructor(
array: Array<E>,
offset: Int,
length: Int,
backing: ArrayList<E>?) {
this.array = array
this.offset = offset
this.length = length
this.backing = backing
}
constructor() {
this.array = arrayOfLateInitElements(10)
this.offset = 0
this.length = 0
this.backing = null
}
constructor(initialCapacity: Int) {
this.array = arrayOfLateInitElements(initialCapacity)
this.offset = 0
this.length = 0
this.backing = null
}
constructor(c: Collection<E>) {
this.array = arrayOfLateInitElements(c.size)
this.offset = 0
this.length = 0
this.backing = null
addAll(c)
}
override val size : Int
get() = length
override fun isEmpty(): Boolean = length == 0
override fun get(index: Int): E {
checkIndex(index)
return array[offset + index]
}
override fun set(index: Int, element: E): E {
checkIndex(index)
val old = array[offset + index]
array[offset + index] = element
return old
}
override fun contains(element: E): Boolean {
var i = 0
while (i < length) {
if (array[offset + i] == element) return true
i++
}
return false
}
override fun containsAll(elements: Collection<E>): Boolean {
val it = elements.iterator()
while (it.hasNext()) {
if (!contains(it.next()))return false
}
return true
}
override fun indexOf(element: E): Int {
var i = 0
while (i < length) {
if (array[offset + i] == element) return i
i++
}
return -1
}
override fun lastIndexOf(element: E): Int {
var i = length - 1
while (i >= 0) {
if (array[offset + i] == element) return i
i--
}
return -1
}
override fun iterator(): MutableIterator<E> = Itr(this, 0)
override fun listIterator(): MutableListIterator<E> = Itr(this, 0)
override fun listIterator(index: Int): MutableListIterator<E> {
checkInsertIndex(index)
return Itr(this, index)
}
override fun add(element: E): Boolean {
addAtInternal(offset + length, element)
return true
}
override fun add(index: Int, element: E) {
checkInsertIndex(index)
addAtInternal(offset + index, element)
}
override fun addAll(elements: Collection<E>): Boolean {
val n = elements.size
addAllInternal(offset + length, elements, n)
return n > 0
}
override fun addAll(index: Int, elements: Collection<E>): Boolean {
checkInsertIndex(index)
val n = elements.size
addAllInternal(offset + index, elements, n)
return n > 0
}
override fun clear() {
removeRangeInternal(offset, length)
}
override fun removeAt(index: Int): E {
checkIndex(index)
return removeAtInternal(offset + index)
}
override fun remove(element: E): Boolean {
val i = indexOf(element)
if (i >= 0) removeAt(i)
return i >= 0
}
override fun removeAll(elements: Collection<E>): Boolean {
var changed = false
val it = elements.iterator()
while (it.hasNext()) {
if (remove(it.next())) changed = true
}
return changed
}
override fun retainAll(elements: Collection<E>): Boolean {
return retainAllInRangeInternal(offset, length, elements) > 0
}
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
checkInsertIndex(fromIndex)
checkInsertIndexFrom(toIndex, fromIndex)
return ArrayList(array, offset + fromIndex, toIndex - fromIndex, this)
}
fun trimToSize() {
if (backing != null) throw IllegalStateException() // just in case somebody casts subList to ArrayList
if (length < array.size)
array = array.copyOfLateInitElements(length)
}
fun ensureCapacity(capacity: Int) {
if (backing != null) throw IllegalStateException() // just in case somebody casts subList to ArrayList
if (capacity > array.size) {
var newSize = array.size * 3 / 2
if (capacity > newSize)
newSize = capacity
array = array.copyOfLateInitElements(newSize)
}
}
override fun equals(other: Any?): Boolean {
//TODO: rethink instance checks, shall it be other is List<*>?
return other === this ||
(other is ArrayList<*>) && contentEquals(other)
}
override fun hashCode(): Int {
var result = 1
var i = 0
while (i < length) {
val nextElement = array[offset + i]
val nextHash = if (nextElement != null) nextElement.hashCode() else 0
result = result * 31 + nextHash
i++
}
return result
}
override fun toString(): String {
var result = "["
var i = 0
while (i < length) {
if (i > 0) result += ", "
result += array[offset + i].toString()
i++
}
result += "]"
return result
}
// ---------------------------- private ----------------------------
private fun ensureExtraCapacity(n: Int) {
ensureCapacity(length + n)
}
private fun checkIndex(index: Int) {
if (index < 0 || index >= length) throw IndexOutOfBoundsException()
}
private fun checkInsertIndex(index: Int) {
if (index < 0 || index > length) throw IndexOutOfBoundsException()
}
private fun checkInsertIndexFrom(index: Int, fromIndex: Int) {
if (index < fromIndex || index > length) throw IndexOutOfBoundsException()
}
private fun contentEquals(other: List<*>): Boolean {
if (length != other.size) return false
var i = 0
while (i < length) {
if (array[offset + i] != other[i]) return false
i++
}
return true
}
private fun insertAtInternal(i: Int, n: Int) {
ensureExtraCapacity(n)
array.copyRange(fromIndex = i, toIndex = offset + length, destinationIndex = i + n)
length += n
}
private fun addAtInternal(i: Int, element: E) {
if (backing != null) {
backing.addAtInternal(i, element)
array = backing.array
// length++ kills translation
length = length + 1
} else {
insertAtInternal(i, 1)
array[i] = element
}
}
private fun addAllInternal(i: Int, elements: Collection<E>, n: Int) {
if (backing != null) {
backing.addAllInternal(i, elements, n)
array = backing.array
length += n
} else {
insertAtInternal(i, n)
var j = 0
val it = elements.iterator()
while (j < n) {
array[i + j] = it.next()
j++
}
}
}
private fun removeAtInternal(i: Int): E {
if (backing != null) {
val old = backing.removeAtInternal(i)
length--
return old
} else {
val old = array[i]
array.copyRange(fromIndex = i + 1, toIndex = offset + length, destinationIndex = i)
array.resetAt(offset + length - 1)
length--
return old
}
}
private fun removeRangeInternal(rangeOffset: Int, rangeLength: Int) {
if (backing != null) {
backing.removeRangeInternal(rangeOffset, rangeLength)
} else {
array.copyRange(fromIndex = rangeOffset + rangeLength, toIndex = length, destinationIndex = rangeOffset)
array.resetRange(fromIndex = length - rangeLength, toIndex = length)
}
length -= rangeLength
}
private fun retainAllInRangeInternal(rangeOffset: Int, rangeLength: Int, elements: Collection<E>): Int {
if (backing != null) {
val removed = backing.retainAllInRangeInternal(rangeOffset, rangeLength, elements)
length -= removed
return removed
} else {
var i = 0
var j = 0
while (i < rangeLength) {
if (elements.contains(array[rangeOffset + i])) {
array[rangeOffset + j++] = array[rangeOffset + i++]
} else {
// TODO: i++ kills translation.
i = i + 1
}
}
val removed = rangeLength - j
array.copyRange(fromIndex = rangeOffset + rangeLength, toIndex = length, destinationIndex = rangeOffset + j)
array.resetRange(fromIndex = length - removed, toIndex = length)
length -= removed
return removed
}
}
private class Itr<E> : MutableListIterator<E> {
private val list: ArrayList<E>
private var index: Int
private var lastIndex: Int
constructor(list: ArrayList<E>, index: Int) {
this.list = list
this.index = index
this.lastIndex = -1
}
override fun hasPrevious(): Boolean = index > 0
override fun hasNext(): Boolean = index < list.length
override fun previousIndex(): Int = index - 1
override fun nextIndex(): Int = index
override fun previous(): E {
if (index <= 0) throw IndexOutOfBoundsException()
lastIndex = --index
return list.array[list.offset + lastIndex]
}
override fun next(): E {
if (index >= list.length) throw IndexOutOfBoundsException()
lastIndex = index++
return list.array[list.offset + lastIndex]
}
override fun set(element: E) {
list.checkIndex(lastIndex)
list.array[list.offset + lastIndex] = element
}
override fun add(element: E) {
list.add(index++, element)
lastIndex = -1
}
override fun remove() {
list.removeAt(lastIndex)
index = lastIndex
lastIndex = -1
}
}
}
@@ -0,0 +1,67 @@
package kotlin.collections
/**
* Returns an array of objects of the given type with the given [size], initialized with **lateinit** _uninitialized_ values.
* Attempts to read _uninitialized_ values from this array work in implementation-dependent manner,
* either throwing exception or returning some kind of implementation-specific default value.
*/
fun <E> arrayOfLateInitElements(size: Int): Array<E> {
// TODO: maybe use an empoty array.
// return (if (size == 0) emptyArray else Array<Any>(size)) as Array<E>
return Array<Any>(size) as Array<E>
}
/**
* Returns new array which is a copy of the original array with new elements filled with **lateinit** _uninitialized_ values.
* Attempts to read _uninitialized_ values from this array work in implementation-dependent manner,
* either throwing exception or returning some kind of implementation-specific default value.
*/
fun <E> Array<E>.copyOfLateInitElements(newSize: Int): Array<E> {
val result = Array<Any>(newSize) as Array<E>
this.copyRangeTo(result, 0, if (newSize > this.size) this.size else newSize, 0)
return result
}
/**
* Resets an array element at a specified index to some implementation-specific _uninitialized_ value.
* In particular, references stored in this element are released and become available for garbage collection.
* Attempts to read _uninitialized_ value work in implementation-dependent manner,
* either throwing exception or returning some kind of implementation-specific default value.
*/
fun <E> Array<E>.resetAt(index: Int) {
(this as Array<Any?>)[index] = null
}
@SymbolName("Kotlin_Array_fillImpl")
external private fun fillImpl(array: Array<Any>, fromIndex: Int, toIndex: Int, value: Any?)
/**
* Resets a range of array elements at a specified [fromIndex] (inclusive) to [toIndex] (exclusive) range of indices
* to some implementation-specific _uninitialized_ value.
* In particular, references stored in these elements are released and become available for garbage collection.
* Attempts to read _uninitialized_ values work in implementation-dependent manner,
* either throwing exception or returning some kind of implementation-specific default value.
*/
fun <E> Array<E>.resetRange(fromIndex: Int, toIndex: Int) {
fillImpl(this as Array<Any>, fromIndex, toIndex, null)
}
@SymbolName("Kotlin_Array_copyImpl")
external private fun copyImpl(array: Array<Any>, fromIndex: Int,
destination: Array<Any>, toIndex: Int, count: Int)
/**
* Copies a range of array elements at a specified [fromIndex] (inclusive) to [toIndex] (exclusive) range of indices
* to another [destination] array starting at [destinationIndex].
*/
fun <E> Array<E>.copyRangeTo(destination: Array<E>, fromIndex: Int, toIndex: Int, destinationIndex: Int = 0) {
copyImpl(this as Array<Any>, fromIndex, destination as Array<Any>, destinationIndex, toIndex - fromIndex)
}
/**
* Copies a range of array elements at a specified [fromIndex] (inclusive) to [toIndex] (exclusive) range of indices
* to another part of this array starting at [destinationIndex].
*/
fun <E> Array<E>.copyRange(fromIndex: Int, toIndex: Int, destinationIndex: Int = 0) {
copyRangeTo(this, fromIndex, toIndex, destinationIndex)
}