Hash map by @elizarov, more stdlib code (#112)

This commit is contained in:
Nikolay Igotti
2016-12-06 13:31:43 +03:00
committed by GitHub
parent 1fc4ce32d3
commit 618bf4cb80
20 changed files with 1734 additions and 212 deletions
@@ -3,11 +3,9 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.types.KotlinType
@@ -4,32 +4,25 @@ import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.backend.konan.llvm.KonanPlatform
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBinaryPrimitiveImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBreakImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetterCallImpl
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) {
@@ -726,7 +719,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun evaluateStringConcatenation(tmpVariableName: String, value: IrStringConcatenation): LLVMValueRef? {
val stringPlus = KonanPlatform.builtIns.stringType.memberScope.getContributedFunctions(Name.identifier("plus"), NoLookupLocation.FROM_BACKEND).first()
val stringPlus = KonanPlatform.builtIns.stringType.memberScope.getContributedFunctions(
Name.identifier("plus"), NoLookupLocation.FROM_BACKEND).first()
var res:LLVMValueRef? = null
val strings:List<LLVMValueRef> = value.arguments.map {
val descriptor = getToString(it.type)
@@ -1464,6 +1458,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
}
descriptor.valueParameters.map {
//println(it.index)
res += (it to expression.getValueArgument(it.index)!!)
}
@@ -1549,6 +1544,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private val kLt0 = Name.identifier("LT0")
private val kLteq0 = Name.identifier("LTEQ0")
private val kNot = Name.identifier("NOT")
private val kThrowNpe = Name.identifier("THROW_NPE")
private val kImmZero = LLVMConstInt(LLVMInt32Type(), 0, 1)!!
private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!!
private val kTrue = LLVMConstInt(LLVMInt1Type(), 1, 1)!!
@@ -1559,13 +1555,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
logger.log("evaluateCall : $tmpVariableName origin:${ir2string(callee)}")
val descriptor = callee.descriptor
when (descriptor.name) {
kEqeq -> return evaluateOperatorEqeq (callee as IrBinaryPrimitiveImpl, args[0]!!, args[1]!!, tmpVariableName)
ktEqeqeq -> return evaluateOperatorEqeqeq(callee as IrBinaryPrimitiveImpl, args[0]!!, args[1]!!, tmpVariableName)
kGt0 -> return codegen.icmpGt(args[0]!!, kImmZero, tmpVariableName)
kGteq0 -> return codegen.icmpGe(args[0]!!, kImmZero, tmpVariableName)
kLt0 -> return codegen.icmpLt(args[0]!!, kImmZero, tmpVariableName)
kLteq0 -> return codegen.icmpLe(args[0]!!, kImmZero, tmpVariableName)
kNot -> return codegen.icmpNe(args[0]!!, kTrue, tmpVariableName)
kEqeq -> return evaluateOperatorEqeq (callee as IrBinaryPrimitiveImpl, args[0]!!, args[1]!!, tmpVariableName)
ktEqeqeq -> return evaluateOperatorEqeqeq(callee as IrBinaryPrimitiveImpl, args[0]!!, args[1]!!, tmpVariableName)
kGt0 -> return codegen.icmpGt(args[0]!!, kImmZero, tmpVariableName)
kGteq0 -> return codegen.icmpGe(args[0]!!, kImmZero, tmpVariableName)
kLt0 -> return codegen.icmpLt(args[0]!!, kImmZero, tmpVariableName)
kLteq0 -> return codegen.icmpLe(args[0]!!, kImmZero, tmpVariableName)
kNot -> return codegen.icmpNe(args[0]!!, kTrue, tmpVariableName)
// TODO: reconsider.
kThrowNpe -> return evaluateOperatorThrowNpe()
else -> {
TODO(descriptor.name.toString())
}
@@ -1574,9 +1572,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun getEquals(type: KotlinType, methodName: String) : SimpleFunctionDescriptor {
private fun getEquals(type: KotlinType) : SimpleFunctionDescriptor {
val name = Name.identifier(methodName)
val name = Name.identifier("equals")
val descriptors = type.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).filter {
it.valueParameters.size == 1 && KotlinBuiltIns.isAnyOrNullableAny(it.valueParameters[0].type)
}
@@ -1593,6 +1591,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
return descriptor
}
private fun getThrowNpe(): SimpleFunctionDescriptor {
val name = Name.identifier("ThrowNullPointerException")
val moduleDescriptor = KonanPlatform.builtIns.builtInsModule
val packageDescriptor = moduleDescriptor.getPackage(FqName("konan.internal"))
val descriptor = packageDescriptor.memberScope.getContributedFunctions(
name, NoLookupLocation.FROM_BACKEND).first()
return descriptor
}
//-------------------------------------------------------------------------//
private fun evaluateOperatorEqeq(callee: IrBinaryPrimitiveImpl, arg0: LLVMValueRef, arg1: LLVMValueRef, tmpVariableName: String): LLVMValueRef {
@@ -1611,14 +1618,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private fun generateEqeqForObjects(callee: IrBinaryPrimitiveImpl, arg0: LLVMValueRef, arg1: LLVMValueRef, tmpVariableName: String): LLVMValueRef {
val arg0Type = callee.argument0.type
val descriptor = getEquals(arg0Type, "equals") // Get descriptor for "arg0.equals".
val descriptor = getEquals(arg0Type) // Get descriptor for "arg0.equals".
if (arg0Type.isMarkedNullable) { // If arg0 is nullable.
val bbEq2 = codegen.basicBlock() // Block to process "eqeq".
val bbEq3 = codegen.basicBlock() // Block to process "eqeqeq".
val bbExit = codegen.basicBlock() // Exit block for feather generation.
val result = codegen.alloca(codegen.getLLVMType(callee.type), codegen.newVar())
val condition = codegen.icmpEq(arg0, codegen.kNullObjHeaderPtr, codegen.newVar()) // Compare arg0 with "null".
val condition = codegen.icmpEq(
arg0, codegen.kNullObjHeaderPtr, codegen.newVar()) // Compare arg0 with "null".
codegen.condBr(condition, bbEq3, bbEq2) // If (arg0 == null) bbEq3 else bbEq2.
codegen.positionAtEnd(bbEq3) // Get generation to bbEq3.
@@ -1653,6 +1661,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
}
}
private fun evaluateOperatorThrowNpe(): LLVMValueRef {
val result = evaluateSimpleFunctionCall("", getThrowNpe(), listOf())
codegen.unreachable()
return result
}
//-------------------------------------------------------------------------//
private fun generateWhenCase(isUnit:Boolean, isNothing:Boolean, resultPtr: LLVMValueRef?, branch: IrBranch, bbNext: LLVMBasicBlockRef?, bbExit: LLVMBasicBlockRef?) {
+10
View File
@@ -477,6 +477,16 @@ task array_list1(type: RunKonanTest) {
source = "runtime/collections/array_list1.kt"
}
task hash_map0(type: RunKonanTest) {
goldValue = "OK\n"
source = "runtime/collections/hash_map0.kt"
}
task hash_set0(type: RunKonanTest) {
goldValue = "OK\n"
source = "runtime/collections/hash_set0.kt"
}
task listof0(type: RunKonanTest) {
goldValue = "abc\n[a, b, c, d]\n[n, s, a]\n"
arguments = ["a"]
@@ -8,12 +8,7 @@ fun assertFalse(cond: Boolean) {
println("FAIL")
}
fun assertEquals(value1: String, value2: String) {
if (value1 != value2)
println("FAIL")
}
fun assertEquals(value1: ArrayList<String>, value2: ArrayList<String>) {
fun assertEquals(value1: Any?, value2: Any?) {
if (value1 != value2)
println("FAIL")
}
@@ -56,77 +51,8 @@ fun testBasic() {
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 a = ArrayList(listOf("1", "2", "3"))
val it = a.iterator()
assertTrue(it.hasNext())
assertEquals("1", it.next())
@@ -137,8 +63,17 @@ fun testIterator() {
assertFalse(it.hasNext())
}
fun testContainsAll() {
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
assertFalse(a.containsAll(listOf("6", "7", "8")))
assertFalse(a.containsAll(listOf("5", "6", "7")))
assertFalse(a.containsAll(listOf("4", "5", "6")))
assertTrue(a.containsAll(listOf("3", "4", "5")))
assertTrue(a.containsAll(listOf("2", "3", "4")))
}
fun testRemove() {
val a = makeList123()
val a = ArrayList(listOf("1", "2", "3"))
assertTrue(a.remove("2"))
assertEquals(2, a.size)
assertEquals("1", a[0])
@@ -150,75 +85,68 @@ fun testRemove() {
}
fun testRemoveAll() {
val a = ArrayList(makeList12345())
assertFalse(a.removeAll(makeList678()))
assertEquals(makeList12345(), a)
assertTrue(a.removeAll(makeList531()))
assertEquals(makeList24(), a)
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
assertFalse(a.removeAll(listOf("6", "7", "8")))
assertEquals(listOf("1", "2", "3", "4", "5"), a)
assertTrue(a.removeAll(listOf("5", "3", "1")))
assertEquals(listOf("2", "4"), a)
}
fun testRetainAll() {
val a = makeList12345()
assertFalse(a.retainAll(makeList12345()))
assertEquals(makeList12345(), a)
assertTrue(a.retainAll(makeList531()))
assertEquals(makeList135(), a)
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
assertFalse(a.retainAll(listOf("1", "2", "3", "4", "5")))
assertEquals(listOf("1", "2", "3", "4", "5"), a)
assertTrue(a.retainAll(listOf("5", "3", "1")))
assertEquals(listOf("1", "3", "5"), a)
}
fun testEquals() {
val a = makeList123()
assertTrue(a == makeList123())
assertFalse(a == makeList135())
assertFalse(a == makeList24())
val a = ArrayList(listOf("1", "2", "3"))
assertTrue(a == listOf("1", "2", "3"))
assertFalse(a == listOf("2", "3", "1")) // order matters
assertFalse(a == listOf("1", "2", "4"))
assertFalse(a == listOf("1", "2"))
}
fun testHashCode() {
val a = makeList123()
assertTrue(a.hashCode() == makeList123().hashCode())
val a = ArrayList(listOf("1", "2", "3"))
assertTrue(a.hashCode() == listOf("1", "2", "3").hashCode())
}
fun testToString() {
val a = makeList123()
assertTrue(a.toString() == makeList123().toString())
}
fun testToString2() {
val a = makeList123()
assertEquals(a.toString(), "[1, 2, 3]")
val a = ArrayList(listOf("1", "2", "3"))
assertTrue(a.toString() == listOf("1", "2", "3").toString())
}
fun testSubList() {
val a0 = makeList01234()
val a0 = ArrayList(listOf("0", "1", "2", "3", "4"))
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())
assertTrue(a == listOf("1", "2", "3"))
assertTrue(a.hashCode() == listOf("1", "2", "3").hashCode())
assertTrue(a.toString() == listOf("1", "2", "3").toString())
}
fun testResize() {
val a = ArrayList<String>()
val n = 10000
var i = 0
while (i++ < n)
for (i in 1..n)
assertTrue(a.add(i.toString()))
assertEquals(n, a.size)
i = 0
while (i++ < n)
for (i in 1..n)
assertEquals(i.toString(), a[i - 1])
a.trimToSize()
assertEquals(n, a.size)
i = 0
while (i++ < n)
for (i in 1..n)
assertEquals(i.toString(), a[i - 1])
}
fun testSubListContains() {
val a = makeList12345()
val a = ArrayList(listOf("1", "2", "3", "4"))
val s = a.subList(1, 3)
assertTrue(a.contains("1"))
assertFalse(s.contains("1"))
@@ -231,7 +159,7 @@ fun testSubListContains() {
}
fun testSubListIndexOf() {
val a = makeList12341()
val a = ArrayList(listOf("1", "2", "3", "4", "1"))
val s = a.subList(1, 3)
assertEquals(0, a.indexOf("1"))
assertEquals(-1, s.indexOf("1"))
@@ -244,7 +172,7 @@ fun testSubListIndexOf() {
}
fun testSubListLastIndexOf() {
val a = makeList12341()
val a = ArrayList(listOf("1", "2", "3", "4", "1"))
val s = a.subList(1, 3)
assertEquals(4, a.lastIndexOf("1"))
assertEquals(-1, s.lastIndexOf("1"))
@@ -256,29 +184,164 @@ fun testSubListLastIndexOf() {
assertEquals(-1, s.lastIndexOf("4"))
}
fun testSubListClear() {
val a = ArrayList(listOf("1", "2", "3", "4"))
val s = a.subList(1, 3)
assertEquals(listOf("2", "3"), s)
s.clear()
assertEquals(listOf<String>(), s)
assertEquals(listOf("1", "4"), a)
}
fun testSubListSubListClear() {
val a = ArrayList(listOf("1", "2", "3", "4", "5", "6"))
val s = a.subList(1, 5)
val q = s.subList(1, 3)
assertEquals(listOf("2", "3", "4", "5"), s)
assertEquals(listOf("3", "4"), q)
q.clear()
assertEquals(listOf<String>(), q)
assertEquals(listOf("2", "5"), s)
assertEquals(listOf("1", "2", "5", "6"), a)
}
fun testSubListAdd() {
val a = ArrayList(listOf("1", "2", "3", "4"))
val s = a.subList(1, 3)
assertEquals(listOf("2", "3"), s)
assertTrue(s.add("5"))
assertEquals(listOf("2", "3", "5"), s)
assertEquals(listOf("1", "2", "3", "5", "4"), a)
}
fun testSubListSubListAdd() {
val a = ArrayList(listOf("1", "2", "3", "4", "5", "6"))
val s = a.subList(1, 5)
val q = s.subList(1, 3)
assertEquals(listOf("2", "3", "4", "5"), s)
assertEquals(listOf("3", "4"), q)
assertTrue(q.add("7"))
assertEquals(listOf("3", "4", "7"), q)
assertEquals(listOf("2", "3", "4", "7", "5"), s)
assertEquals(listOf("1", "2", "3", "4", "7", "5", "6"), a)
}
fun testSubListAddAll() {
val a = ArrayList(listOf("1", "2", "3", "4"))
val s = a.subList(1, 3)
assertEquals(listOf("2", "3"), s)
assertTrue(s.addAll(listOf("5", "6")))
assertEquals(listOf("2", "3", "5", "6"), s)
assertEquals(listOf("1", "2", "3", "5", "6", "4"), a)
}
fun testSubListSubListAddAll() {
val a = ArrayList(listOf("1", "2", "3", "4", "5", "6"))
val s = a.subList(1, 5)
val q = s.subList(1, 3)
assertEquals(listOf("2", "3", "4", "5"), s)
assertEquals(listOf("3", "4"), q)
assertTrue(q.addAll(listOf("7", "8")))
assertEquals(listOf("3", "4", "7", "8"), q)
assertEquals(listOf("2", "3", "4", "7", "8", "5"), s)
assertEquals(listOf("1", "2", "3", "4", "7", "8", "5", "6"), a)
}
fun testSubListRemoveAt() {
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
val s = a.subList(1, 4)
assertEquals(listOf("2", "3", "4"), s)
assertEquals("3", s.removeAt(1))
assertEquals(listOf("2", "4"), s)
assertEquals(listOf("1", "2", "4", "5"), a)
}
fun testSubListSubListRemoveAt() {
val a = ArrayList(listOf("1", "2", "3", "4", "5", "6", "7"))
val s = a.subList(1, 6)
val q = s.subList(1, 4)
assertEquals(listOf("2", "3", "4", "5", "6"), s)
assertEquals(listOf("3", "4", "5"), q)
assertEquals("4", q.removeAt(1))
assertEquals(listOf("3", "5"), q)
assertEquals(listOf("2", "3", "5", "6"), s)
assertEquals(listOf("1", "2", "3", "5", "6", "7"), a)
}
fun testSubListRemoveAll() {
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
val s = a.subList(1, 4)
assertEquals(listOf("2", "3", "4"), s)
assertTrue(s.removeAll(listOf("3", "5")))
assertEquals(listOf("2", "4"), s)
assertEquals(listOf("1", "2", "4", "5"), a)
}
fun testSubListSubListRemoveAll() {
val a = ArrayList(listOf("1", "2", "3", "4", "5", "6", "7"))
val s = a.subList(1, 6)
val q = s.subList(1, 4)
assertEquals(listOf("2", "3", "4", "5", "6"), s)
assertEquals(listOf("3", "4", "5"), q)
assertTrue(q.removeAll(listOf("4", "6")))
assertEquals(listOf("3", "5"), q)
assertEquals(listOf("2", "3", "5", "6"), s)
assertEquals(listOf("1", "2", "3", "5", "6", "7"), a)
}
fun testSubListRetainAll() {
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
val s = a.subList(1, 4)
assertEquals(listOf("2", "3", "4"), s)
assertTrue(s.retainAll(listOf("5", "3")))
assertEquals(listOf("3"), s)
assertEquals(listOf("1", "3", "5"), a)
}
fun testSubListSubListRetainAll() {
val a = ArrayList(listOf("1", "2", "3", "4", "5", "6", "7"))
val s = a.subList(1, 6)
val q = s.subList(1, 4)
assertEquals(listOf("2", "3", "4", "5", "6"), s)
assertEquals(listOf("3", "4", "5"), q)
assertTrue(q.retainAll(listOf("5", "3")))
assertEquals(listOf("3", "5"), q)
assertEquals(listOf("2", "3", "5", "6"), s)
assertEquals(listOf("1", "2", "3", "5", "6", "7"), a)
}
fun testIteratorRemove() {
val a = makeList12345()
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
val it = a.iterator()
while (it.hasNext())
if (it.next()[0].toInt() % 2 == 0)
it.remove()
assertEquals(makeList135(), a)
assertEquals(listOf("1", "3", "5"), a)
}
fun testIteratorAdd() {
val a = makeList12345()
val a = ArrayList(listOf("1", "2", "3", "4", "5"))
val it = a.listIterator()
var i = 1
while (it.hasNext()) {
val next = it.next()
if (i++ % 2 == 0)
if (next[0].toInt() % 2 == 0)
it.add("-" + next)
}
assertEquals("[1, 2, -2, 3, 4, -4, 5]", a.toString())
assertEquals(listOf("1", "2", "-2", "3", "4", "-4", "5"), a)
}
fun main(args : Array<String>) {
testBasic()
testIterator()
@@ -288,13 +351,27 @@ fun main(args : Array<String>) {
testEquals()
testHashCode()
testToString()
testToString2()
testSubList()
testResize()
testSubListContains()
testSubListIndexOf()
testSubListLastIndexOf()
testIteratorAdd()
/*
testSubListClear()
testSubListSubListClear()
testSubListAdd()
testSubListSubListAdd()
testSubListAddAll()
testSubListSubListAddAll()
testSubListRemoveAt()
testSubListSubListRemoveAt()
testSubListRemoveAll()
testSubListSubListRemoveAll()
testSubListSubListRemoveAll()
testSubListRetainAll()
testSubListSubListRetainAll() */
testIteratorRemove()
testIteratorAdd()
println("OK")
}
@@ -0,0 +1,157 @@
fun assertTrue(cond: Boolean) {
if (!cond)
println("FAIL")
}
fun assertFalse(cond: Boolean) {
if (cond)
println("FAIL")
}
fun assertEquals(value1: Any?, value2: Any?) {
if (value1 != value2)
println("FAIL")
}
fun assertEquals(value1: Int, value2: Int) {
if (value1 != value2)
println("FAIL")
}
fun testBasic() {
val m = HashMap<String, String>()
assertTrue(m.isEmpty())
assertEquals(0, m.size)
assertFalse(m.containsKey("1"))
assertFalse(m.containsValue("a"))
assertEquals(null, m.get("1"))
assertEquals(null, m.put("1", "a"))
assertTrue(m.containsKey("1"))
assertTrue(m.containsValue("a"))
assertEquals("a", m.get("1"))
assertFalse(m.isEmpty())
assertEquals(1, m.size)
assertFalse(m.containsKey("2"))
assertFalse(m.containsValue("b"))
assertEquals(null, m.get("2"))
assertEquals(null, m.put("2", "b"))
assertTrue(m.containsKey("1"))
assertTrue(m.containsValue("a"))
assertEquals("a", m.get("1"))
assertTrue(m.containsKey("2"))
assertTrue(m.containsValue("b"))
assertEquals("b", m.get("2"))
assertFalse(m.isEmpty())
assertEquals(2, m.size)
assertEquals("b", m.put("2", "bb"))
assertTrue(m.containsKey("1"))
assertTrue(m.containsValue("a"))
assertEquals("a", m.get("1"))
assertTrue(m.containsKey("2"))
assertTrue(m.containsValue("a"))
assertTrue(m.containsValue("bb"))
assertEquals("bb", m.get("2"))
assertFalse(m.isEmpty())
assertEquals(2, m.size)
assertEquals("a", m.remove("1"))
assertFalse(m.containsKey("1"))
assertFalse(m.containsValue("a"))
assertEquals(null, m.get("1"))
assertTrue(m.containsKey("2"))
assertTrue(m.containsValue("bb"))
assertEquals("bb", m.get("2"))
assertFalse(m.isEmpty())
assertEquals(1, m.size)
assertEquals("bb", m.remove("2"))
assertFalse(m.containsKey("1"))
assertFalse(m.containsValue("a"))
assertEquals(null, m.get("1"))
assertFalse(m.containsKey("2"))
assertFalse(m.containsValue("bb"))
assertEquals(null, m.get("2"))
assertTrue(m.isEmpty())
assertEquals(0, m.size)
}
fun testRehashAndCompact() {
val m = HashMap<String, String>()
for (repeat in 1..10) {
val n = when (repeat) {
1 -> 1000
2 -> 10000
3 -> 10
else -> 100000
}
for (i in 1..n) {
assertFalse(m.containsKey(i.toString()))
assertEquals(null, m.put(i.toString(), "val$i"))
assertTrue(m.containsKey(i.toString()))
assertEquals(i, m.size)
}
for (i in 1..n) {
assertTrue(m.containsKey(i.toString()))
}
for (i in 1..n) {
assertEquals("val$i", m.remove(i.toString()))
assertFalse(m.containsKey(i.toString()))
assertEquals(n - i, m.size)
}
assertTrue(m.isEmpty())
}
}
fun testClear() {
val m = HashMap<String, String>()
for (repeat in 1..10) {
val n = when (repeat) {
1 -> 1000
2 -> 10000
3 -> 10
else -> 100000
}
for (i in 1..n) {
assertFalse(m.containsKey(i.toString()))
assertEquals(null, m.put(i.toString(), "val$i"))
assertTrue(m.containsKey(i.toString()))
assertEquals(i, m.size)
}
for (i in 1..n) {
assertTrue(m.containsKey(i.toString()))
}
m.clear()
assertEquals(0, m.size)
for (i in 1..n) {
assertFalse(m.containsKey(i.toString()))
}
}
}
// 'to' not yet working.
/*
fun testEquals() {
val expected = mapOf("a" to "1", "b" to "2", "c" to "3")
val m = HashMap(expected)
assertTrue(m == expected)
assertTrue(m == mapOf("b" to "2", "c" to "3", "a" to "1")) // order does not matter
assertFalse(m == mapOf("a" to "1", "b" to "2", "c" to "4"))
assertFalse(m == mapOf("a" to "1", "b" to "2", "c" to "5"))
assertFalse(m == mapOf("a" to "1", "b" to "2"))
assertEquals(m.keys, expected.keys)
assertEquals(m.values, expected.values)
assertEquals(m.entries, expected.entries)
} */
fun main(args : Array<String>) {
testBasic()
testRehashAndCompact()
testClear()
//testEquals()
println("OK")
}
@@ -0,0 +1,131 @@
fun assertTrue(cond: Boolean) {
if (!cond)
println("FAIL")
}
fun assertFalse(cond: Boolean) {
if (cond)
println("FAIL")
}
fun assertEquals(value1: Any?, value2: Any?) {
if (value1 != value2)
println("FAIL")
}
fun assertEquals(value1: Int, value2: Int) {
if (value1 != value2)
println("FAIL")
}
fun testBasic() {
val a = HashSet<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)
assertTrue(a.contains("1"))
assertTrue(a.contains("2"))
assertTrue(a.contains("3"))
assertFalse(a.contains("4"))
assertTrue(a.remove("1"))
assertEquals(2, a.size)
assertFalse(a.contains("1"))
assertTrue(a.contains("2"))
assertTrue(a.contains("3"))
assertFalse(a.contains("4"))
assertTrue(a.add("4"))
assertEquals(3, a.size)
assertFalse(a.contains("1"))
assertTrue(a.contains("2"))
assertTrue(a.contains("3"))
assertTrue(a.contains("4"))
assertFalse(a.add("4"))
assertEquals(3, a.size)
assertFalse(a.contains("1"))
assertTrue(a.contains("2"))
assertTrue(a.contains("3"))
assertTrue(a.contains("4"))
a.clear()
assertTrue(a.isEmpty())
assertEquals(0, a.size)
assertFalse(a.contains("1"))
assertFalse(a.contains("2"))
assertFalse(a.contains("3"))
assertFalse(a.contains("4"))
}
fun testIterator() {
val s = HashSet(listOf("1", "2", "3"))
val it = s.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 testEquals() {
val s = HashSet(listOf("1", "2", "3"))
assertTrue(s == setOf("1", "2", "3"))
assertTrue(s == setOf("2", "3", "1")) // order does not matter
assertFalse(s == setOf("1", "2", "4"))
assertFalse(s == setOf("1", "2"))
}
fun testHashCode() {
val s = HashSet(listOf("1", "2", "3"))
assertTrue(s.hashCode() == setOf("1", "2", "3").hashCode())
}
fun testToString() {
val s = HashSet(listOf("1", "2", "3"))
assertTrue(s.toString() == setOf("1", "2", "3").toString())
}
fun testContainsAll() {
val s = HashSet(listOf("1", "2", "3", "4", "5"))
assertFalse(s.containsAll(listOf("6", "7", "8")))
assertFalse(s.containsAll(listOf("5", "6", "7")))
assertFalse(s.containsAll(listOf("4", "5", "6")))
assertTrue(s.containsAll(listOf("3", "4", "5")))
assertTrue(s.containsAll(listOf("2", "3", "4")))
}
fun testRemoveAll() {
val s = HashSet(listOf("1", "2", "3", "4", "5"))
assertFalse(s.removeAll(listOf("6", "7", "8")))
assertEquals(setOf("1", "2", "3", "4", "5"), s)
assertTrue(s.removeAll(listOf("5", "3", "1")))
assertEquals(setOf("2", "4"), s)
}
fun testRetainAll() {
val s = HashSet(listOf("1", "2", "3", "4", "5"))
assertFalse(s.retainAll(listOf("1", "2", "3", "4", "5")))
assertEquals(setOf("1", "2", "3", "4", "5"), s)
assertTrue(s.retainAll(listOf("5", "3", "1")))
assertEquals(setOf("1", "3", "5"), s)
}
fun main(args : Array<String>) {
testBasic()
testIterator()
testEquals()
testHashCode()
testToString()
testContainsAll()
testRemoveAll()
testRetainAll()
println("OK")
}
+68 -43
View File
@@ -12,7 +12,7 @@ extern "C" {
// TODO: those must be compiler intrinsics afterwards.
// Array.kt
KRef Kotlin_Array_get(const ObjHeader* thiz, KInt index) {
KRef Kotlin_Array_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -20,7 +20,7 @@ KRef Kotlin_Array_get(const ObjHeader* thiz, KInt index) {
return *ArrayAddressOfElementAt(array, index);
}
void Kotlin_Array_set(ObjHeader* thiz, KInt index, KConstRef value) {
void Kotlin_Array_set(KRef thiz, KInt index, KConstRef value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -28,7 +28,7 @@ void Kotlin_Array_set(ObjHeader* thiz, KInt index, KConstRef value) {
*ArrayAddressOfElementAt(array, index) = value;
}
ObjHeader* Kotlin_Array_clone(const ObjHeader* thiz) {
KRef Kotlin_Array_clone(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
array->type_info(), array->count_).GetPlace();
@@ -39,15 +39,14 @@ ObjHeader* Kotlin_Array_clone(const ObjHeader* thiz) {
return result;
}
KInt Kotlin_Array_getArrayLength(const ObjHeader* thiz) {
KInt Kotlin_Array_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
return array->count_;
}
void Kotlin_Array_fillImpl(ObjHeader* thiz, KInt fromIndex,
KInt toIndex, ObjHeader* value) {
void Kotlin_Array_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KRef value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (fromIndex < 0 || toIndex < fromIndex || toIndex >= array->count_) {
if (fromIndex < 0 || toIndex < fromIndex || toIndex > array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
// TODO: refcounting!
@@ -56,8 +55,8 @@ void Kotlin_Array_fillImpl(ObjHeader* thiz, KInt fromIndex,
}
}
void Kotlin_Array_copyImpl(const ObjHeader* thiz, KInt fromIndex,
ObjHeader* destination, KInt toIndex, KInt count) {
void Kotlin_Array_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* destinationArray = static_cast<ArrayHeader*>(destination);
if (fromIndex < 0 || fromIndex + count > array->count_ ||
@@ -70,7 +69,7 @@ void Kotlin_Array_copyImpl(const ObjHeader* thiz, KInt fromIndex,
}
// Arrays.kt
KByte Kotlin_ByteArray_get(const ObjHeader* thiz, KInt index) {
KByte Kotlin_ByteArray_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -78,7 +77,7 @@ KByte Kotlin_ByteArray_get(const ObjHeader* thiz, KInt index) {
return *ByteArrayAddressOfElementAt(array, index);
}
void Kotlin_ByteArray_set(ObjHeader* thiz, KInt index, KByte value) {
void Kotlin_ByteArray_set(KRef thiz, KInt index, KByte value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -86,7 +85,7 @@ void Kotlin_ByteArray_set(ObjHeader* thiz, KInt index, KByte value) {
*ByteArrayAddressOfElementAt(array, index) = value;
}
ObjHeader* Kotlin_ByteArray_clone(const ObjHeader* thiz) {
KRef Kotlin_ByteArray_clone(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
theByteArrayTypeInfo, array->count_).GetPlace();
@@ -97,12 +96,12 @@ ObjHeader* Kotlin_ByteArray_clone(const ObjHeader* thiz) {
return result;
}
KInt Kotlin_ByteArray_getArrayLength(const ObjHeader* thiz) {
KInt Kotlin_ByteArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
return array->count_;
}
KChar Kotlin_CharArray_get(const ObjHeader* thiz, KInt index) {
KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -110,7 +109,7 @@ KChar Kotlin_CharArray_get(const ObjHeader* thiz, KInt index) {
return *PrimitiveArrayAddressOfElementAt<KChar>(array, index);
}
void Kotlin_CharArray_set(ObjHeader* thiz, KInt index, KChar value) {
void Kotlin_CharArray_set(KRef thiz, KInt index, KChar value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -118,7 +117,7 @@ void Kotlin_CharArray_set(ObjHeader* thiz, KInt index, KChar value) {
*PrimitiveArrayAddressOfElementAt<KChar>(array, index) = value;
}
ObjHeader* Kotlin_CharArray_clone(const ObjHeader* thiz) {
KRef Kotlin_CharArray_clone(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
theCharArrayTypeInfo, array->count_).GetPlace();
@@ -129,7 +128,7 @@ ObjHeader* Kotlin_CharArray_clone(const ObjHeader* thiz) {
return result;
}
ObjHeader* Kotlin_CharArray_copyOf(const ObjHeader* thiz, KInt newSize) {
KRef Kotlin_CharArray_copyOf(KConstRef thiz, KInt newSize) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
theCharArrayTypeInfo, newSize).GetPlace();
@@ -141,12 +140,12 @@ ObjHeader* Kotlin_CharArray_copyOf(const ObjHeader* thiz, KInt newSize) {
return result;
}
KInt Kotlin_CharArray_getArrayLength(const ObjHeader* thiz) {
KInt Kotlin_CharArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
return array->count_;
}
KShort Kotlin_ShortArray_get(const ObjHeader* thiz, KInt index) {
KShort Kotlin_ShortArray_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -154,7 +153,7 @@ KShort Kotlin_ShortArray_get(const ObjHeader* thiz, KInt index) {
return *PrimitiveArrayAddressOfElementAt<KShort>(array, index);
}
void Kotlin_ShortArray_set(ObjHeader* thiz, KInt index, KShort value) {
void Kotlin_ShortArray_set(KRef thiz, KInt index, KShort value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -162,7 +161,8 @@ void Kotlin_ShortArray_set(ObjHeader* thiz, KInt index, KShort value) {
*PrimitiveArrayAddressOfElementAt<KShort>(array, index) = value;
}
ArrayHeader* Kotlin_ShortArray_clone(const ArrayHeader* array) {
KRef Kotlin_ShortArray_clone(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
theShortArrayTypeInfo, array->count_).GetPlace();
memcpy(
@@ -172,11 +172,12 @@ ArrayHeader* Kotlin_ShortArray_clone(const ArrayHeader* array) {
return result;
}
KInt Kotlin_ShortArray_getArrayLength(const ArrayHeader* array) {
KInt Kotlin_ShortArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
return array->count_;
}
KInt Kotlin_IntArray_get(const ObjHeader* thiz, KInt index) {
KInt Kotlin_IntArray_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -184,7 +185,7 @@ KInt Kotlin_IntArray_get(const ObjHeader* thiz, KInt index) {
return *PrimitiveArrayAddressOfElementAt<KInt>(array, index);
}
void Kotlin_IntArray_set(ObjHeader* thiz, KInt index, KInt value) {
void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -192,7 +193,7 @@ void Kotlin_IntArray_set(ObjHeader* thiz, KInt index, KInt value) {
*PrimitiveArrayAddressOfElementAt<KInt>(array, index) = value;
}
ObjHeader* Kotlin_IntArray_clone(const ObjHeader* thiz) {
ObjHeader* Kotlin_IntArray_clone(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
theIntArrayTypeInfo, array->count_).GetPlace();
@@ -203,20 +204,44 @@ ObjHeader* Kotlin_IntArray_clone(const ObjHeader* thiz) {
return result;
}
KInt Kotlin_IntArray_getArrayLength(const ObjHeader* thiz) {
KInt Kotlin_IntArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
return array->count_;
}
KLong Kotlin_LongArray_get(const ObjHeader* thiz, KInt index) {
void Kotlin_IntArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KInt value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (fromIndex < 0 || toIndex < fromIndex || toIndex >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
for (KInt index = fromIndex; index < toIndex; ++index) {
*PrimitiveArrayAddressOfElementAt<KInt>(array, index) = value;
}
}
void Kotlin_IntArray_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* destinationArray = static_cast<ArrayHeader*>(destination);
if (fromIndex < 0 || fromIndex + count > array->count_ ||
toIndex < 0 || toIndex + count > destinationArray->count_) {
ThrowArrayIndexOutOfBoundsException();
}
memmove(PrimitiveArrayAddressOfElementAt<KInt>(destinationArray, toIndex),
PrimitiveArrayAddressOfElementAt<KInt>(array, fromIndex),
count * sizeof(KInt));
}
KLong Kotlin_LongArray_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
ThrowArrayIndexOutOfBoundsException();
}
return *PrimitiveArrayAddressOfElementAt<KLong>(array, index);
}
void Kotlin_LongArray_set(ObjHeader* thiz, KInt index, KLong value) {
void Kotlin_LongArray_set(KRef thiz, KInt index, KLong value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -224,7 +249,7 @@ void Kotlin_LongArray_set(ObjHeader* thiz, KInt index, KLong value) {
*PrimitiveArrayAddressOfElementAt<KLong>(array, index) = value;
}
ArrayHeader* Kotlin_LongArray_clone(const ObjHeader* thiz) {
KRef Kotlin_LongArray_clone(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
theLongArrayTypeInfo, array->count_).GetPlace();
@@ -235,12 +260,12 @@ ArrayHeader* Kotlin_LongArray_clone(const ObjHeader* thiz) {
return result;
}
KInt Kotlin_LongArray_getArrayLength(const ObjHeader* thiz) {
KInt Kotlin_LongArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
return array->count_;
}
KFloat Kotlin_FloatArray_get(const ObjHeader* thiz, KInt index) {
KFloat Kotlin_FloatArray_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -248,7 +273,7 @@ KFloat Kotlin_FloatArray_get(const ObjHeader* thiz, KInt index) {
return *PrimitiveArrayAddressOfElementAt<KFloat>(array, index);
}
void Kotlin_FloatArray_set(ObjHeader* thiz, KInt index, KFloat value) {
void Kotlin_FloatArray_set(KRef thiz, KInt index, KFloat value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -256,7 +281,7 @@ void Kotlin_FloatArray_set(ObjHeader* thiz, KInt index, KFloat value) {
*PrimitiveArrayAddressOfElementAt<KFloat>(array, index) = value;
}
ArrayHeader* Kotlin_FloatArray_clone(const ObjHeader* thiz) {
ArrayHeader* Kotlin_FloatArray_clone(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
theFloatArrayTypeInfo, array->count_).GetPlace();
@@ -267,12 +292,12 @@ ArrayHeader* Kotlin_FloatArray_clone(const ObjHeader* thiz) {
return result;
}
KInt Kotlin_FloatArray_getArrayLength(const ObjHeader* thiz) {
KInt Kotlin_FloatArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
return array->count_;
}
KDouble Kotlin_DoubleArray_get(const ObjHeader* thiz, KInt index) {
KDouble Kotlin_DoubleArray_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -280,7 +305,7 @@ KDouble Kotlin_DoubleArray_get(const ObjHeader* thiz, KInt index) {
return *PrimitiveArrayAddressOfElementAt<KDouble>(array, index);
}
void Kotlin_DoubleArray_set(ObjHeader* thiz, KInt index, KDouble value) {
void Kotlin_DoubleArray_set(KRef thiz, KInt index, KDouble value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -288,7 +313,7 @@ void Kotlin_DoubleArray_set(ObjHeader* thiz, KInt index, KDouble value) {
*PrimitiveArrayAddressOfElementAt<KDouble>(array, index) = value;
}
ObjHeader* Kotlin_DoubleArray_clone(const ObjHeader* thiz) {
KRef Kotlin_DoubleArray_clone(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
theDoubleArrayTypeInfo, array->count_).GetPlace();
@@ -299,12 +324,12 @@ ObjHeader* Kotlin_DoubleArray_clone(const ObjHeader* thiz) {
return result;
}
KInt Kotlin_DoubleArray_getArrayLength(const ObjHeader* thiz) {
KInt Kotlin_DoubleArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
return array->count_;
}
KBoolean Kotlin_BooleanArray_get(const ObjHeader* thiz, KInt index) {
KBoolean Kotlin_BooleanArray_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -312,7 +337,7 @@ KBoolean Kotlin_BooleanArray_get(const ObjHeader* thiz, KInt index) {
return *PrimitiveArrayAddressOfElementAt<KBoolean>(array, index);
}
void Kotlin_BooleanArray_set(ObjHeader* thiz, KInt index, KBoolean value) {
void Kotlin_BooleanArray_set(KRef thiz, KInt index, KBoolean value) {
ArrayHeader* array = static_cast<ArrayHeader*>(thiz);
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
@@ -320,7 +345,7 @@ void Kotlin_BooleanArray_set(ObjHeader* thiz, KInt index, KBoolean value) {
*PrimitiveArrayAddressOfElementAt<KBoolean>(array, index) = value;
}
ObjHeader* Kotlin_BooleanArray_clone(const ObjHeader* thiz) {
KRef Kotlin_BooleanArray_clone(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
ArrayHeader* result = ArrayContainer(
theBooleanArrayTypeInfo, array->count_).GetPlace();
@@ -331,7 +356,7 @@ ObjHeader* Kotlin_BooleanArray_clone(const ObjHeader* thiz) {
return result;
}
KInt Kotlin_BooleanArray_getArrayLength(const ObjHeader* thiz) {
KInt Kotlin_BooleanArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = static_cast<const ArrayHeader*>(thiz);
return array->count_;
}
+8
View File
@@ -191,6 +191,14 @@ KInt Kotlin_Int_dec (KInt a ) { return --a; }
KInt Kotlin_Int_unaryPlus (KInt a ) { return +a; }
KInt Kotlin_Int_unaryMinus (KInt a ) { return -a; }
KInt Kotlin_Int_xor_Int (KInt a, KInt b) { return a ^ b; }
KInt Kotlin_Int_and_Int (KInt a, KInt b) { return a & b; }
KInt Kotlin_Int_shl_Int (KInt a, KInt b) { return a << b; }
KInt Kotlin_Int_shr_Int (KInt a, KInt b) { return a >> b; }
KInt Kotlin_Int_ushr_Int (KInt a, KInt b) {
return static_cast<uint32_t>(a) >> b;
}
KByte Kotlin_Int_toByte (KInt a ) { return a; }
KChar Kotlin_Int_toChar (KInt a ) { return a; }
KShort Kotlin_Int_toShort (KInt a ) { return a; }
@@ -1,13 +1,12 @@
package kotlin
// TODO: shouldn't these annotation be located in 'kotlin_native.internal' package?
/**
* Suppresses the given compilation warnings in the annotated element.
* @property names names of the compiler diagnostics to suppress.
*/
//@Target(CLASS, ANNOTATION_CLASS, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER,
// CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPE, EXPRESSION, FILE, TYPEALIAS)
@Target(AnnotationTarget.TYPE, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
//@Retention(SOURCE)
public annotation class Suppress(vararg val names: String)
+2
View File
@@ -35,3 +35,5 @@ public open class Any {
@SymbolName("Kotlin_Any_toString")
external public open fun toString(): String
}
public fun Any?.hashCode() = if (this != null) this.hashCode() else 0
+1
View File
@@ -23,6 +23,7 @@ public final class Array<T> : Cloneable {
return IteratorImpl(this)
}
// Konan-specific.
@SymbolName("Kotlin_Array_getArrayLength")
external private fun getArrayLength(): Int
}
@@ -647,6 +647,32 @@ public final class Int : Number(), Comparable<Int> {
public override fun hashCode(): Int {
return this
}
fun highestOneBit() : Int {
var index = 31
while (index >= 0) {
var mask = (1 shl index)
if ((mask and this) != 0) {
return mask
}
index--
}
return 0
}
fun numberOfLeadingZeros() : Int {
var index = 31
while (index >= 0) {
var mask = (1 shl index)
if ((mask and this) != 0) {
return 31 - index
}
index--
}
return 0
}
}
/**
@@ -9,7 +9,8 @@ class ArrayList<E> private constructor(
constructor() : this(10)
constructor(initialCapacity: Int) : this(arrayOfLateInitElements(initialCapacity), 0, 0, null)
constructor(initialCapacity: Int) : this(
arrayOfUninitializedElements(initialCapacity), 0, 0, null)
constructor(c: Collection<E>) : this(c.size) {
addAll(c)
@@ -135,7 +136,7 @@ class ArrayList<E> private constructor(
fun trimToSize() {
if (backing != null) throw IllegalStateException() // just in case somebody casts subList to ArrayList
if (length < array.size)
array = array.copyOfLateInitElements(length)
array = array.copyOfUninitializedElements(length)
}
fun ensureCapacity(capacity: Int) {
@@ -144,7 +145,7 @@ class ArrayList<E> private constructor(
var newSize = array.size * 3 / 2
if (capacity > newSize)
newSize = capacity
array = array.copyOfLateInitElements(newSize)
array = array.copyOfUninitializedElements(newSize)
}
}
@@ -5,8 +5,7 @@ package kotlin.collections
* 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 empty array.
fun <E> arrayOfUninitializedElements(size: Int): Array<E> {
// return (if (size == 0) emptyArray else Array<Any>(size)) as Array<E>
return Array<E>(size)
}
@@ -16,12 +15,18 @@ fun <E> arrayOfLateInitElements(size: Int): Array<E> {
* 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> {
fun <E> Array<E>.copyOfUninitializedElements(newSize: Int): Array<E> {
val result = Array<E>(newSize)
this.copyRangeTo(result, 0, if (newSize > this.size) this.size else newSize, 0)
return result
}
fun IntArray.copyOfUninitializedElements(newSize: Int): IntArray {
val result = IntArray(newSize)
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.
@@ -35,6 +40,9 @@ fun <E> Array<E>.resetAt(index: Int) {
@SymbolName("Kotlin_Array_fillImpl")
external private fun fillImpl(array: Array<Any>, fromIndex: Int, toIndex: Int, value: Any?)
@SymbolName("Kotlin_IntArray_fillImpl")
external private fun fillImpl(array: IntArray, fromIndex: Int, toIndex: Int, value: Int)
/**
* Resets a range of array elements at a specified [fromIndex] (inclusive) to [toIndex] (exclusive) range of indices
* to some implementation-specific _uninitialized_ value.
@@ -46,10 +54,18 @@ fun <E> Array<E>.resetRange(fromIndex: Int, toIndex: Int) {
fillImpl(this as Array<Any>, fromIndex, toIndex, null)
}
fun IntArray.fill(fromIndex: Int, toIndex: Int, value: Int) {
fillImpl(this, fromIndex, toIndex, value)
}
@SymbolName("Kotlin_Array_copyImpl")
external private fun copyImpl(array: Array<Any>, fromIndex: Int,
destination: Array<Any>, toIndex: Int, count: Int)
@SymbolName("Kotlin_IntArray_copyImpl")
external private fun copyImpl(array: IntArray, fromIndex: Int,
destination: IntArray, 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].
@@ -58,10 +74,29 @@ fun <E> Array<E>.copyRangeTo(destination: Array<E>, fromIndex: Int, toIndex: Int
copyImpl(this as Array<Any>, fromIndex, destination as Array<Any>, destinationIndex, toIndex - fromIndex)
}
fun IntArray.copyRangeTo(destination: IntArray, fromIndex: Int, toIndex: Int, destinationIndex: Int = 0) {
copyImpl(this, fromIndex, destination, 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)
}
internal fun <E> Collection<E>.collectionToString(): String {
val sb = StringBuilder(2 + size * 3)
sb.append("[")
var i = 0
val it = iterator()
while (it.hasNext()) {
if (i > 0) sb.append(", ")
val next = it.next()
if (next == this) sb.append("(this Collection)") else sb.append(next)
i++
}
sb.append("]")
return sb.toString()
}
@@ -32,6 +32,14 @@ fun <E> Array<E>.asList(): List<E> {
return result
}
fun <E> Array<E>.toSet(): Set<E> {
val result = HashSet<E>(this.size)
for (e in this) {
result.add(e)
}
return result
}
public fun <T> arrayListOf(vararg args: T): MutableList<T> {
val result = ArrayList<T>(args.size)
for (arg in args) {
@@ -40,8 +48,24 @@ public fun <T> arrayListOf(vararg args: T): MutableList<T> {
return result
}
public fun <T> hashSetOf(vararg args: T): HashSet<T> {
val result = HashSet<T>(args.size)
for (arg in args) {
result.add(arg)
}
return result
}
// TODO: implement EmptySet and EmptyList objects.
/*
* TODO: in Big Kotlin this function is following: (see libraries/stdlib/src/kotlin/collections/Collections.kt)
* public fun <T> listOf(vararg elements: T): List<T> = if (elements.size > 0) elements.asList() else emptyList()
*/
public fun <T> listOf(vararg args: T): List<T> = args.asList()
public fun <T> listOf(): List<T> = ArrayList(0)
public fun <T> listOf(vararg args: T): List<T> = args.asList()
public fun <T> setOf(vararg args: T): Set<T> = args.toSet()
public fun <T> mutableSetOf(vararg args: T): MutableSet<T> = HashSet<T>(args.asList())
@@ -0,0 +1,670 @@
package kotlin.collections
// TODO: remove
private val MAGIC: Long = 2654435769 // golden ratio
private val INITIAL_CAPACITY = 8
private val INITIAL_MAX_PROBE_DISTANCE = 2
private val TOMBSTONE = -1
private fun computeHashSize(capacity: Int): Int = (capacity.coerceAtLeast(1) * 3).highestOneBit()
private fun computeShift(hashSize: Int): Int = hashSize.numberOfLeadingZeros() + 1
class HashMap<K, V> private constructor(
private var keysArray: Array<K>,
private var valuesArray: Array<V>?, // allocated only when actually used, always null in pure HashSet
private var presenceArray: IntArray,
private var hashArray: IntArray,
private var maxProbeDistance: Int,
private var length: Int
) : MutableMap<K, V> {
private var hashShift: Int = computeShift(hashSize)
override var size: Int = 0
private set
private var keysView: HashSet<K>? = null
private var valuesView: HashMapValues<V>? = null
private var entriesView: HashMapEntrySet<K, V>? = null
// ---------------------------- functions ----------------------------
constructor() : this(INITIAL_CAPACITY)
constructor(capacity: Int) : this(
arrayOfUninitializedElements(capacity),
null,
IntArray(capacity),
IntArray(computeHashSize(capacity)),
INITIAL_MAX_PROBE_DISTANCE,
0)
constructor(m: Map<K, V>) : this(m.size) {
putAll(m)
}
override fun isEmpty(): Boolean = size == 0
override fun containsKey(key: K): Boolean = findKey(key) >= 0
override fun containsValue(value: V): Boolean = findValue(value) >= 0
override fun get(key: K): V? {
val index = findKey(key)
if (index < 0) return null
return valuesArray!![index]
}
override fun put(key: K, value: V): V? {
val index = addKey(key)
val valuesArray = allocateValuesArray()
if (index < 0) {
val oldValue = valuesArray[-index - 1]
valuesArray[-index - 1] = value
return oldValue
} else {
valuesArray[index] = value
return null
}
}
override fun putAll(from: Map<out K, V>) {
putAllEntries(from.entries)
}
override fun remove(key: K): V? {
val index = removeKey(key)
if (index < 0) return null
val valuesArray = valuesArray!!
val oldValue = valuesArray[index]
valuesArray.resetAt(index)
return oldValue
}
override fun clear() {
// O(length) implementation for hashArray cleanup
for (i in 0..length - 1) {
val hash = presenceArray[i]
if (hash >= 0) {
hashArray[hash] = 0
presenceArray[i] = TOMBSTONE
}
}
keysArray.resetRange(0, length)
valuesArray?.resetRange(0, length)
size = 0
length = 0
}
override val keys: MutableSet<K> get() {
val cur = keysView
return if (cur == null) {
val new = HashSet(this)
keysView = new
new
} else cur
}
override val values: MutableCollection<V> get() {
val cur = valuesView
return if (cur == null) {
val new = HashMapValues(this)
valuesView = new
new
} else cur
}
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() {
val cur = entriesView
return if (cur == null) {
val new = HashMapEntrySet(this)
entriesView = new
return new
} else cur
}
override fun equals(other: Any?): Boolean {
return other === this ||
(other is Map<*, *>) &&
contentEquals(other)
}
override fun hashCode(): Int {
var result = 0
val it = entriesIterator()
while (it.hasNext()) {
result += it.nextHashCode()
}
return result
}
override fun toString(): String {
val sb = StringBuilder(2 + size * 3)
sb.append("{")
var i = 0
val it = entriesIterator()
while (it.hasNext()) {
if (i > 0) sb.append(", ")
it.nextAppendString(sb)
i++
}
sb.append("}")
return sb.toString()
}
// ---------------------------- private ----------------------------
private val capacity: Int get() = keysArray.size
private val hashSize: Int get() = hashArray.size
private fun ensureExtraCapacity(n: Int) {
ensureCapacity(length + n)
}
private fun ensureCapacity(capacity: Int) {
if (capacity > this.capacity) {
var newSize = this.capacity * 3 / 2
if (capacity > newSize) newSize = capacity
keysArray = keysArray.copyOfUninitializedElements(newSize)
valuesArray = valuesArray?.copyOfUninitializedElements(newSize)
presenceArray = presenceArray.copyOfUninitializedElements(newSize)
val newHashSize = computeHashSize(newSize)
if (newHashSize > hashSize) rehash(newHashSize)
} else if (length + capacity - size > this.capacity) {
rehash(hashSize)
}
}
private fun allocateValuesArray(): Array<V> {
val curValuesArray = valuesArray
if (curValuesArray != null) return curValuesArray
val newValuesArray = arrayOfUninitializedElements<V>(capacity)
valuesArray = newValuesArray
return newValuesArray
}
private fun hash(key: K) = (key.hashCode() * MAGIC.toInt()) ushr hashShift
private fun compact() {
var i = 0
var j = 0
val valuesArray = valuesArray
while (i < length) {
if (presenceArray[i] >= 0) {
keysArray[j] = keysArray[i]
if (valuesArray != null) valuesArray[j] = valuesArray[i]
j++
}
i++
}
keysArray.resetRange(j, length)
valuesArray?.resetRange(j, length)
length = j
//check(length == size) { "Internal invariant violated during compact: length=$length != size=$size" }
}
private fun rehash(newHashSize: Int) {
if (length > size) compact()
if (newHashSize != hashSize) {
hashArray = IntArray(newHashSize)
hashShift = computeShift(newHashSize)
} else {
hashArray.fill(0, 0, hashSize)
}
var i = 0
while (i < length) {
if (!putRehash(i++)) {
throw IllegalStateException("This cannot happen with fixed magic multiplier and grow-only hash array. " +
"Have object hashCodes changed?")
}
}
}
private fun putRehash(i: Int): Boolean {
var hash = hash(keysArray[i])
var probesLeft = maxProbeDistance
while (true) {
val index = hashArray[hash]
if (index == 0) {
hashArray[hash] = i + 1
presenceArray[i] = hash
return true
}
if (--probesLeft < 0) return false
if (hash-- == 0) hash = hashSize - 1
}
}
private fun findKey(key: K): Int {
var hash = hash(key)
var probesLeft = maxProbeDistance
while (true) {
val index = hashArray[hash]
if (index == 0) return TOMBSTONE
if (index > 0 && keysArray[index - 1] == key) return index - 1
if (--probesLeft < 0) return TOMBSTONE
if (hash-- == 0) hash = hashSize - 1
}
}
private fun findValue(value: V): Int {
var i = length
while (--i >= 0) {
if (presenceArray[i] >= 0 && valuesArray!![i] == value)
return i
}
return TOMBSTONE
}
internal fun addKey(key: K): Int {
retry@ while (true) {
var hash = hash(key)
// put is allowed to grow maxProbeDistance with some limits (resize hash on reaching limits)
val tentativeMaxProbeDistance = (maxProbeDistance * 2).coerceAtMost(hashSize / 2)
var probeDistance = 0
while (true) {
val index = hashArray[hash]
if (index <= 0) { // claim or reuse hash slot
if (length >= capacity) {
ensureExtraCapacity(1)
continue@retry
}
val putIndex = length++
keysArray[putIndex] = key
presenceArray[putIndex] = hash
hashArray[hash] = putIndex + 1
size++
if (probeDistance > maxProbeDistance) maxProbeDistance = probeDistance
return putIndex
}
if (keysArray[index - 1] == key) {
return -index
}
if (++probeDistance > tentativeMaxProbeDistance) {
rehash(hashSize * 2) // cannot find room even with extra "tentativeMaxProbeDistance" -- grow hash
continue@retry
}
if (hash-- == 0) hash = hashSize - 1
}
}
}
internal fun removeKey(key: K): Int {
val index = findKey(key)
if (index < 0) return TOMBSTONE
removeKeyAt(index)
return index
}
private fun removeKeyAt(index: Int) {
keysArray.resetAt(index)
removeHashAt(presenceArray[index])
presenceArray[index] = TOMBSTONE
size--
}
private fun removeHashAt(removedHash: Int) {
var hash = removedHash
var hole = removedHash // will try to patch the hole in hash array
var probeDistance = 0
var patchAttemptsLeft = (maxProbeDistance * 2).coerceAtMost(hashSize / 2) // don't spend too much effort
while (true) {
if (hash-- == 0) hash = hashSize - 1
if (++probeDistance > maxProbeDistance) {
// too far away -- can release the hole, bad case will not happen
hashArray[hole] = 0
return
}
val index = hashArray[hash]
if (index == 0) {
// end of chain -- can release the hole, bad case will not happen
hashArray[hole] = 0
return
}
if (index < 0) {
// TOMBSTONE FOUND
// - <--- [ TS ] ------ [hole] ---> +
// \------------/
// probeDistance
// move tombstone into the hole
hashArray[hole] = TOMBSTONE
hole = hash
probeDistance = 0
} else {
val otherHash = hash(keysArray[index - 1])
// Bad case:
// - <--- [hash] ------ [hole] ------ [otherHash] ---> +
// \------------/
// probeDistance
if ((otherHash - hash) and (hashSize - 1) >= probeDistance) {
// move otherHash into the hole, move the hole
hashArray[hole] = index
presenceArray[index - 1] = hole
hole = hash
probeDistance = 0
}
}
// check how long we're patching holes
if (--patchAttemptsLeft < 0) {
// just place tombstone into the hole
hashArray[hole] = TOMBSTONE
return
}
}
}
internal fun containsEntry(entry: Map.Entry<K, V>): Boolean {
val index = findKey(entry.key)
if (index < 0) return false
return valuesArray!![index] == entry.value
}
private fun contentEquals(other: Map<*, *>): Boolean = size == other.size && containsAllEntries(other.entries)
internal fun containsAllEntries(m: Collection<Map.Entry<*, *>>): Boolean {
val it = m.iterator()
while (it.hasNext()) {
val entry = it.next()
try {
@Suppress("UNCHECKED_CAST") // todo: get rid of unchecked cast here somehow
if (!containsEntry(entry as Map.Entry<K, V>))
return false
} catch(e: ClassCastException) {
return false
}
}
return true
}
internal fun putEntry(entry: Map.Entry<K, V>): Boolean {
val index = addKey(entry.key)
val valuesArray = allocateValuesArray()
if (index >= 0) {
valuesArray[index] = entry.value
return true
}
val oldValue = valuesArray[-index - 1]
if (entry.value != oldValue) {
valuesArray[-index - 1] = entry.value
return true
}
return false
}
internal fun putAllEntries(from: Collection<Map.Entry<K, V>>): Boolean {
if (from.isEmpty()) return false
ensureExtraCapacity(from.size)
val it = from.iterator()
var updated = false
while (it.hasNext()) {
if (putEntry(it.next()))
updated = true
}
return updated
}
internal fun removeEntry(entry: Map.Entry<K, V>): Boolean {
val index = findKey(entry.key)
if (index < 0) return false
if (valuesArray!![index] != entry.value) return false
removeKeyAt(index)
return true
}
internal fun removeAllEntries(elements: Collection<Map.Entry<K, V>>): Boolean {
if (elements.isEmpty()) return false
val it = elements.iterator()
var updated = false
while (it.hasNext()) {
if (removeEntry(it.next()))
updated = true
}
return updated
}
internal fun retainAllEntries(elements: Collection<Map.Entry<K, V>>): Boolean {
val it = entriesIterator()
var updated = false
while (it.hasNext()) {
if (!elements.contains(it.next())) {
it.remove()
updated = true
}
}
return updated
}
internal fun containsAllValues(elements: Collection<V>): Boolean {
val it = elements.iterator()
while (it.hasNext()) {
if (!containsValue(it.next()))
return false
}
return true
}
internal fun removeValue(element: V): Boolean {
val index = findValue(element)
if (index < 0) return false
removeKeyAt(index)
return true
}
internal fun removeAllValues(elements: Collection<V>): Boolean {
val it = elements.iterator()
var updated = false
while (it.hasNext()) {
if (removeValue(it.next()))
updated = true
}
return updated
}
internal fun retainAllValues(elements: Collection<V>): Boolean {
val it = valuesIterator()
var updated = false
while (it.hasNext()) {
if (!elements.contains(it.next())) {
it.remove()
updated = true
}
}
return updated
}
internal fun keysIterator() = KeysItr(this)
internal fun valuesIterator() = ValuesItr(this)
internal fun entriesIterator() = EntriesItr(this)
// TODO: fix!
/* private companion object {
const val MAGIC = 2654435769L.toInt() // golden ratio
const val INITIAL_CAPACITY = 8
const val INITIAL_MAX_PROBE_DISTANCE = 2
const val TOMBSTONE = -1
fun computeHashSize(capacity: Int): Int = (capacity.coerceAtLeast(1) * 3).highestOneBit()
fun computeShift(hashSize: Int): Int = hashSize.numberOfLeadingZeros() + 1
} */
internal open class Itr<K, V>(
internal val map: HashMap<K, V>
) {
internal var index = 0
internal var lastIndex: Int = -1
init {
initNext()
}
internal fun initNext() {
while (index < map.length && map.presenceArray[index] < 0)
index++
}
fun hasNext(): Boolean = index < map.length
fun remove() {
map.removeKeyAt(lastIndex)
lastIndex = -1
}
}
internal class KeysItr<K, V>(map: HashMap<K, V>) : Itr<K, V>(map), MutableIterator<K> {
override fun next(): K {
if (index >= map.length) throw IndexOutOfBoundsException()
lastIndex = index++
val result = map.keysArray[lastIndex]
initNext()
return result
}
}
internal class ValuesItr<K, V>(map: HashMap<K, V>) : Itr<K, V>(map), MutableIterator<V> {
override fun next(): V {
if (index >= map.length) throw IndexOutOfBoundsException()
lastIndex = index++
val result = map.valuesArray!![lastIndex]
initNext()
return result
}
}
internal class EntriesItr<K, V>(map: HashMap<K, V>) : Itr<K, V>(map),
MutableIterator<MutableMap.MutableEntry<K, V>> {
override fun next(): EntryRef<K, V> {
if (index >= map.length) throw IndexOutOfBoundsException()
lastIndex = index++
val result = EntryRef(map, lastIndex)
initNext()
return result
}
internal fun nextHashCode(): Int {
if (index >= map.length) throw IndexOutOfBoundsException()
lastIndex = index++
val result = map.keysArray[lastIndex].hashCode() xor map.valuesArray!![lastIndex].hashCode()
initNext()
return result
}
fun nextAppendString(sb: StringBuilder) {
if (index >= map.length) throw IndexOutOfBoundsException()
lastIndex = index++
val key = map.keysArray[lastIndex]
if (key == map) sb.append("(this Map)") else sb.append(key)
sb.append('=')
val value = map.valuesArray!![lastIndex]
if (value == map) sb.append("(this Map)") else sb.append(value)
initNext()
}
}
internal class EntryRef<K, V>(
private val map: HashMap<K, V>,
private val index: Int
) : MutableMap.MutableEntry<K, V> {
override val key: K
get() = map.keysArray[index]
override val value: V
get() = map.valuesArray!![index]
override fun setValue(newValue: V): V {
val valuesArray = map.allocateValuesArray()
val oldValue = valuesArray[index]
valuesArray[index] = newValue
return oldValue
}
override fun equals(other: Any?): Boolean =
other is Map.Entry<*, *> &&
other.key == key &&
other.value == value
override fun hashCode(): Int = key.hashCode() xor value.hashCode()
override fun toString(): String = "$key=$value"
}
}
internal class HashMapValues<V> internal constructor(
val backing: HashMap<*, V>
) : MutableCollection<V> {
override val size: Int get() = backing.size
override fun isEmpty(): Boolean = backing.isEmpty()
override fun contains(element: V): Boolean = backing.containsValue(element)
override fun containsAll(elements: Collection<V>): Boolean = backing.containsAllValues(elements)
override fun add(element: V): Boolean = throw UnsupportedOperationException()
override fun addAll(elements: Collection<V>): Boolean = throw UnsupportedOperationException()
override fun clear() = backing.clear()
override fun iterator(): MutableIterator<V> = backing.valuesIterator()
override fun remove(element: V): Boolean = backing.removeValue(element)
override fun removeAll(elements: Collection<V>): Boolean = backing.removeAllValues(elements)
override fun retainAll(elements: Collection<V>): Boolean = backing.retainAllValues(elements)
override fun equals(other: Any?): Boolean =
other === this ||
other is Collection<*> &&
contentEquals(other)
override fun hashCode(): Int {
var result = 1
val it = iterator()
while (it.hasNext()) {
result = result * 31 + it.next().hashCode()
}
return result
}
override fun toString(): String = collectionToString()
// ---------------------------- private ----------------------------
private fun contentEquals(other: Collection<*>): Boolean {
@Suppress("UNCHECKED_CAST") // todo: figure out something better
return size == other.size && backing.containsAllValues(other as Collection<V>)
}
}
internal class HashMapEntrySet<K, V> internal constructor(
val backing: HashMap<K, V>
) : MutableSet<MutableMap.MutableEntry<K, V>> {
override val size: Int get() = backing.size
override fun isEmpty(): Boolean = backing.isEmpty()
override fun contains(element: MutableMap.MutableEntry<K, V>): Boolean = backing.containsEntry(element)
override fun clear() = backing.clear()
override fun add(element: MutableMap.MutableEntry<K, V>): Boolean = backing.putEntry(element)
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean = backing.removeEntry(element)
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = backing.entriesIterator()
override fun containsAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean = backing.containsAllEntries(elements)
override fun addAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean = backing.putAllEntries(elements)
override fun removeAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean = backing.removeAllEntries(elements)
override fun retainAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean = backing.retainAllEntries(elements)
override fun equals(other: Any?): Boolean =
other === this ||
other is Set<*> &&
contentEquals(other)
override fun hashCode(): Int {
var result = 0
val it = iterator()
while (it.hasNext()) {
result += it.next().hashCode()
}
return result
}
override fun toString(): String = collectionToString()
// ---------------------------- private ----------------------------
private fun contentEquals(other: Set<*>): Boolean {
@Suppress("UNCHECKED_CAST") // todo: get rid of unchecked cast here somehow
return size == other.size && backing.containsAllEntries(other as Collection<Map.Entry<*, *>>)
}
}
@@ -0,0 +1,84 @@
package kotlin.collections
class HashSet<K> internal constructor(
val backing: HashMap<K, *>
) : MutableSet<K> {
constructor() : this(HashMap<K, Nothing>())
constructor(capacity: Int) : this(HashMap<K, Nothing>(capacity))
constructor(c: Collection<K>) : this(c.size) {
addAll(c)
}
override val size: Int get() = backing.size
override fun isEmpty(): Boolean = backing.isEmpty()
override fun contains(element: K): Boolean = backing.containsKey(element)
override fun clear() = backing.clear()
override fun add(element: K): Boolean = backing.addKey(element) >= 0
override fun remove(element: K): Boolean = backing.removeKey(element) >= 0
override fun iterator(): MutableIterator<K> = backing.keysIterator()
override fun containsAll(elements: Collection<K>): Boolean {
val it = elements.iterator()
while (it.hasNext()) {
if (!contains(it.next()))
return false
}
return true
}
override fun addAll(elements: Collection<K>): Boolean {
val it = elements.iterator()
var updated = false
while (it.hasNext()) {
if (add(it.next()))
updated = true
}
return updated
}
override fun removeAll(elements: Collection<K>): Boolean {
val it = elements.iterator()
var updated = false
while (it.hasNext()) {
if (remove(it.next()))
updated = true
}
return updated
}
override fun retainAll(elements: Collection<K>): Boolean {
val it = iterator()
var updated = false
while (it.hasNext()) {
if (!elements.contains(it.next())) {
it.remove()
updated = true
}
}
return updated
}
override fun equals(other: Any?): Boolean {
return other === this ||
(other is Set<*>) &&
contentEquals(other as Set<K>)
}
override fun hashCode(): Int {
var result = 0
val it = iterator()
while (it.hasNext()) {
result += it.next().hashCode()
}
return result
}
override fun toString(): String = collectionToString()
// ---------------------------- private ----------------------------
private fun contentEquals(other: Set<K>): Boolean = size == other.size && containsAll(other)
}
@@ -0,0 +1,27 @@
package kotlin.collections
fun Int.highestOneBit() : Int {
var index = 31
while (index >= 0) {
var mask = (1 shl index)
if ((mask and this) != 0) {
return mask
}
index--
}
return 0
}
fun Int.numberOfLeadingZeros() : Int {
var index = 31
while (index >= 0) {
var mask = (1 shl index)
if ((mask and this) != 0) {
return 31 - index
}
index--
}
return 0
}
@@ -35,13 +35,6 @@ public interface Map<K, out V> {
*/
public operator fun get(key: K): V?
/**
* Returns the value corresponding to the given [key], or [defaultValue] if such a key is not present in the map.
*
* @since JDK 1.8
*/
public fun getOrDefault(key: K, defaultValue: @UnsafeVariance V): V
// Views
/**
* Returns a [Set] of all keys in this map.
@@ -96,13 +89,6 @@ public interface MutableMap<K, V> : Map<K, V> {
*/
public fun remove(key: K): V?
/**
* Removes the entry for the specified key only if it is mapped to the specified value.
*
* @return true if entry was removed
*/
public fun remove(key: K, value: V): Boolean
// Bulk Modification Operations
/**
* Updates this map with key/value pairs from the specified map [from].
+248 -1
View File
@@ -76,4 +76,251 @@ public class LongRange(start: Long, endInclusive: Long) : LongProgression(start,
/** An empty range of values of type Long. */
public val EMPTY: LongRange = LongRange(1, 0)
}
}
}
/**
* Ensures that this value is not less than the specified [minimumValue].
*
* @return this value if it's greater than or equal to the [minimumValue] or the
[minimumValue] otherwise.
*/
public fun <T: Comparable<T>> T.coerceAtLeast(minimumValue: T): T {
return if (this < minimumValue) minimumValue else this
}
/**
* Ensures that this value is not less than the specified [minimumValue].
*
* @return this value if it's greater than or equal to the [minimumValue] or the [minimumValue] otherwise.
*/
public fun Byte.coerceAtLeast(minimumValue: Byte): Byte {
return if (this < minimumValue) minimumValue else this
}
/**
* Ensures that this value is not less than the specified [minimumValue].
*
* @return this value if it's greater than or equal to the [minimumValue] or the [minimumValue] otherwise.
*/
public fun Short.coerceAtLeast(minimumValue: Short): Short {
return if (this < minimumValue) minimumValue else this
}
/**
* Ensures that this value is not less than the specified [minimumValue].
*
* @return this value if it's greater than or equal to the [minimumValue] or the [minimumValue] otherwise.
*/
public fun Int.coerceAtLeast(minimumValue: Int): Int {
return if (this < minimumValue) minimumValue else this
}
/**
* Ensures that this value is not less than the specified [minimumValue].
*
* @return this value if it's greater than or equal to the [minimumValue] or the [minimumValue] otherwise.
*/
public fun Long.coerceAtLeast(minimumValue: Long): Long {
return if (this < minimumValue) minimumValue else this
}
/**
* Ensures that this value is not less than the specified [minimumValue].
*
* @return this value if it's greater than or equal to the [minimumValue] or the [minimumValue] otherwise.
*/
public fun Float.coerceAtLeast(minimumValue: Float): Float {
return if (this < minimumValue) minimumValue else this
}
/**
* Ensures that this value is not less than the specified [minimumValue].
*
* @return this value if it's greater than or equal to the [minimumValue] or the [minimumValue] otherwise.
*/
public fun Double.coerceAtLeast(minimumValue: Double): Double {
return if (this < minimumValue) minimumValue else this
}
/**
* Ensures that this value is not greater than the specified [maximumValue].
*
* @return this value if it's less than or equal to the [maximumValue] or the [maximumValue] otherwise.
*/
public fun <T: Comparable<T>> T.coerceAtMost(maximumValue: T): T {
return if (this > maximumValue) maximumValue else this
}
/**
* Ensures that this value is not greater than the specified [maximumValue].
*
* @return this value if it's less than or equal to the [maximumValue] or the [maximumValue] otherwise.
*/
public fun Byte.coerceAtMost(maximumValue: Byte): Byte {
return if (this > maximumValue) maximumValue else this
}
/**
* Ensures that this value is not greater than the specified [maximumValue].
*
* @return this value if it's less than or equal to the [maximumValue] or the [maximumValue] otherwise.
*/
public fun Short.coerceAtMost(maximumValue: Short): Short {
return if (this > maximumValue) maximumValue else this
}
/**
* Ensures that this value is not greater than the specified [maximumValue].
*
* @return this value if it's less than or equal to the [maximumValue] or the [maximumValue] otherwise.
*/
public fun Int.coerceAtMost(maximumValue: Int): Int {
return if (this > maximumValue) maximumValue else this
}
/**
* Ensures that this value is not greater than the specified [maximumValue].
*
* @return this value if it's less than or equal to the [maximumValue] or the [maximumValue] otherwise.
*/
public fun Long.coerceAtMost(maximumValue: Long): Long {
return if (this > maximumValue) maximumValue else this
}
/**
* Ensures that this value is not greater than the specified [maximumValue].
*
* @return this value if it's less than or equal to the [maximumValue] or the [maximumValue] otherwise.
*/
public fun Float.coerceAtMost(maximumValue: Float): Float {
return if (this > maximumValue) maximumValue else this
}
/**
* Ensures that this value is not greater than the specified [maximumValue].
*
* @return this value if it's less than or equal to the [maximumValue] or the [maximumValue] otherwise.
*/
public fun Double.coerceAtMost(maximumValue: Double): Double {
return if (this > maximumValue) maximumValue else this
}
/**
* Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
*
* @return this value if it's in the range, or [minimumValue] if this value is less than [minimumValue], or [maximumValue] if this value is greater than [maximumValue].
*/
public fun <T: Comparable<T>> T.coerceIn(minimumValue: T?, maximumValue: T?): T {
if (minimumValue !== null && maximumValue !== null) {
if (minimumValue > maximumValue) throw IllegalArgumentException("Cannot coerce value to an empty range: maximum $maximumValue is less than minimum $minimumValue.")
if (this < minimumValue) return minimumValue
if (this > maximumValue) return maximumValue
}
else {
if (minimumValue !== null && this < minimumValue) return minimumValue
if (maximumValue !== null && this > maximumValue) return maximumValue
}
return this
}
/**
* Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
*
* @return this value if it's in the range, or [minimumValue] if this value is less than [minimumValue], or [maximumValue] if this value is greater than [maximumValue].
*/
public fun Byte.coerceIn(minimumValue: Byte, maximumValue: Byte): Byte {
if (minimumValue > maximumValue) throw IllegalArgumentException("Cannot coerce value to an empty range: maximum $maximumValue is less than minimum $minimumValue.")
if (this < minimumValue) return minimumValue
if (this > maximumValue) return maximumValue
return this
}
/**
* Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
*
* @return this value if it's in the range, or [minimumValue] if this value is less than [minimumValue], or [maximumValue] if this value is greater than [maximumValue].
*/
public fun Short.coerceIn(minimumValue: Short, maximumValue: Short): Short {
if (minimumValue > maximumValue) throw IllegalArgumentException("Cannot coerce value to an empty range: maximum $maximumValue is less than minimum $minimumValue.")
if (this < minimumValue) return minimumValue
if (this > maximumValue) return maximumValue
return this
}
/**
* Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
*
* @return this value if it's in the range, or [minimumValue] if this value is less than [minimumValue], or [maximumValue] if this value is greater than [maximumValue].
*/
public fun Int.coerceIn(minimumValue: Int, maximumValue: Int): Int {
if (minimumValue > maximumValue) throw IllegalArgumentException("Cannot coerce value to an empty range: maximum $maximumValue is less than minimum $minimumValue.")
if (this < minimumValue) return minimumValue
if (this > maximumValue) return maximumValue
return this
}
/**
* Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
*
* @return this value if it's in the range, or [minimumValue] if this value is less than [minimumValue], or [maximumValue] if this value is greater than [maximumValue].
*/
public fun Long.coerceIn(minimumValue: Long, maximumValue: Long): Long {
if (minimumValue > maximumValue) throw IllegalArgumentException("Cannot coerce value to an empty range: maximum $maximumValue is less than minimum $minimumValue.")
if (this < minimumValue) return minimumValue
if (this > maximumValue) return maximumValue
return this
}
/**
* Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
*
* @return this value if it's in the range, or [minimumValue] if this value is less than [minimumValue], or [maximumValue] if this value is greater than [maximumValue].
*/
public fun Float.coerceIn(minimumValue: Float, maximumValue: Float): Float {
if (minimumValue > maximumValue) throw IllegalArgumentException("Cannot coerce value to an empty range: maximum $maximumValue is less than minimum $minimumValue.")
if (this < minimumValue) return minimumValue
if (this > maximumValue) return maximumValue
return this
}
/**
* Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
*
* @return this value if it's in the range, or [minimumValue] if this value is less than [minimumValue], or [maximumValue] if this value is greater than [maximumValue].
*/
public fun Double.coerceIn(minimumValue: Double, maximumValue: Double): Double {
if (minimumValue > maximumValue) throw IllegalArgumentException("Cannot coerce value to an empty range: maximum $maximumValue is less than minimum $minimumValue.")
if (this < minimumValue) return minimumValue
if (this > maximumValue) return maximumValue
return this
}
/**
* Ensures that this value lies in the specified [range].
*
* @return this value if it's in the [range], or range.start if this value is less than range.start, or range.end if this value is greater than range.end.
*/
public fun <T: Comparable<T>> T.coerceIn(range: ClosedRange<T>): T {
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
return if (this < range.start) range.start else if (this > range.endInclusive) range.endInclusive else this
}
/**
* Ensures that this value lies in the specified [range].
*
* @return this value if it's in the [range], or range.start if this value is less than range.start, or range.end if this value is greater than range.end.
*/
public fun Int.coerceIn(range: ClosedRange<Int>): Int {
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
return if (this < range.start) range.start else if (this > range.endInclusive) range.endInclusive else this
}
/**
* Ensures that this value lies in the specified [range].
*
* @return this value if it's in the [range], or range.start if this value is less than range.start, or range.end if this value is greater than range.end.
*/
public fun Long.coerceIn(range: ClosedRange<Long>): Long {
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
return if (this < range.start) range.start else if (this > range.endInclusive) range.endInclusive else this
}