Hash map by @elizarov, more stdlib code (#112)
This commit is contained in:
-2
@@ -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
|
||||
|
||||
|
||||
+34
-20
@@ -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?) {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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_;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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].
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user