kotlinx.atomicfu compiler plugin for JS_IR backend (#4581)
* kotlinx.atomicfu compiler plugin for JS_IR Support transformations of atomic operations introduced by the kotlinx.atomicfu library for the JS_IR backend. Compiler plugin is applied externally by the kotlinx.atomicfu gradle plugin. * Apply compiler plugin for JS platform only * New plugin test structure * testGroupOutputDirPrefix changed
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class IntArithmetic {
|
||||
val _x = atomic(0)
|
||||
val x get() = _x.value
|
||||
}
|
||||
|
||||
class LongArithmetic {
|
||||
val _x = atomic(4294967296)
|
||||
val x get() = _x.value
|
||||
val y = atomic(5000000000)
|
||||
val z = atomic(2424920024888888848)
|
||||
val max = atomic(9223372036854775807)
|
||||
}
|
||||
|
||||
class BooleanArithmetic {
|
||||
val _x = atomic(false)
|
||||
val x get() = _x.value
|
||||
}
|
||||
|
||||
class ReferenceArithmetic {
|
||||
val _x = atomic<String?>(null)
|
||||
}
|
||||
|
||||
class ArithmeticTest {
|
||||
val local = atomic(0)
|
||||
|
||||
fun testGetValue() {
|
||||
val a = IntArithmetic()
|
||||
a._x.value = 5
|
||||
check(a._x.value == 5)
|
||||
var aValue = a._x.value
|
||||
check(aValue == 5)
|
||||
check(a.x == 5)
|
||||
|
||||
local.value = 555
|
||||
aValue = local.value
|
||||
check(local.value == aValue)
|
||||
}
|
||||
|
||||
fun testAtomicCallPlaces(): Boolean {
|
||||
val a = IntArithmetic()
|
||||
a._x.value = 5
|
||||
a._x.compareAndSet(5, 42)
|
||||
val res = a._x.compareAndSet(42, 45)
|
||||
check(res)
|
||||
check(a._x.compareAndSet(45, 77))
|
||||
check(!a._x.compareAndSet(95, 77))
|
||||
return a._x.compareAndSet(77, 88)
|
||||
}
|
||||
|
||||
fun testInt() {
|
||||
val a = IntArithmetic()
|
||||
check(a.x == 0)
|
||||
val update = 3
|
||||
check(a._x.getAndSet(update) == 0)
|
||||
check(a._x.compareAndSet(update, 8))
|
||||
a._x.lazySet(1)
|
||||
check(a.x == 1)
|
||||
check(a._x.getAndSet(2) == 1)
|
||||
check(a.x == 2)
|
||||
check(a._x.getAndIncrement() == 2)
|
||||
check(a.x == 3)
|
||||
check(a._x.getAndDecrement() == 3)
|
||||
check(a.x == 2)
|
||||
check(a._x.getAndAdd(2) == 2)
|
||||
check(a.x == 4)
|
||||
check(a._x.addAndGet(3) == 7)
|
||||
check(a.x == 7)
|
||||
check(a._x.incrementAndGet() == 8)
|
||||
check(a.x == 8)
|
||||
check(a._x.decrementAndGet() == 7)
|
||||
check(a.x == 7)
|
||||
check(a._x.compareAndSet(7, 10))
|
||||
}
|
||||
|
||||
fun testLong() {
|
||||
val a = LongArithmetic()
|
||||
check(a.z.value == 2424920024888888848)
|
||||
a.z.lazySet(8424920024888888848)
|
||||
check(a.z.value == 8424920024888888848)
|
||||
check(a.z.getAndSet(8924920024888888848) == 8424920024888888848)
|
||||
check(a.z.value == 8924920024888888848)
|
||||
check(a.z.incrementAndGet() == 8924920024888888849) // fails
|
||||
check(a.z.value == 8924920024888888849)
|
||||
check(a.z.getAndDecrement() == 8924920024888888849)
|
||||
check(a.z.value == 8924920024888888848)
|
||||
check(a.z.getAndAdd(100000000000000000) == 8924920024888888848)
|
||||
check(a.z.value == 9024920024888888848)
|
||||
check(a.z.addAndGet(-9223372036854775807) == -198452011965886959)
|
||||
check(a.z.value == -198452011965886959)
|
||||
check(a.z.incrementAndGet() == -198452011965886958)
|
||||
check(a.z.value == -198452011965886958)
|
||||
check(a.z.decrementAndGet() == -198452011965886959)
|
||||
check(a.z.value == -198452011965886959)
|
||||
}
|
||||
|
||||
fun testBoolean() {
|
||||
val a = BooleanArithmetic()
|
||||
check(!a.x)
|
||||
a._x.lazySet(true)
|
||||
check(a.x)
|
||||
check(a._x.getAndSet(true))
|
||||
check(a._x.compareAndSet(true, false))
|
||||
check(!a.x)
|
||||
}
|
||||
|
||||
fun testReference() {
|
||||
val a = ReferenceArithmetic()
|
||||
a._x.value = "aaa"
|
||||
check(a._x.value == "aaa")
|
||||
a._x.lazySet("bb")
|
||||
check(a._x.value == "bb")
|
||||
check(a._x.getAndSet("ccc") == "bb")
|
||||
check(a._x.value == "ccc")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = ArithmeticTest()
|
||||
|
||||
testClass.testGetValue()
|
||||
if (!testClass.testAtomicCallPlaces()) return "testAtomicCallPlaces: FAILED"
|
||||
|
||||
testClass.testInt()
|
||||
testClass.testLong()
|
||||
testClass.testBoolean()
|
||||
testClass.testReference()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class ArrayInlineFunctionTest {
|
||||
private val anyArr = atomicArrayOfNulls<Any?>(5)
|
||||
private val refArr = atomicArrayOfNulls<Box>(5)
|
||||
|
||||
private data class Box(val n: Int)
|
||||
|
||||
fun testSetArrayElementValueInLoop() {
|
||||
anyArr[0].loop { cur ->
|
||||
assertTrue(anyArr[0].compareAndSet(cur, IntArray(5)))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun action(cur: Box?) = cur?.let { Box(cur.n * 10) }
|
||||
|
||||
|
||||
fun testArrayElementUpdate() {
|
||||
refArr[0].lazySet(Box(5))
|
||||
refArr[0].update { cur -> cur?.let { Box(cur.n * 10) } }
|
||||
assertEquals(refArr[0].value!!.n, 50)
|
||||
}
|
||||
|
||||
|
||||
fun testArrayElementGetAndUpdate() {
|
||||
refArr[0].lazySet(Box(5))
|
||||
assertEquals(refArr[0].getAndUpdate { cur -> action(cur) }!!.n, 5)
|
||||
assertEquals(refArr[0].value!!.n, 50)
|
||||
}
|
||||
|
||||
|
||||
fun testArrayElementUpdateAndGet() {
|
||||
refArr[0].lazySet(Box(5))
|
||||
assertEquals(refArr[0].updateAndGet { cur -> action(cur) }!!.n, 50)
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = ArrayInlineFunctionTest()
|
||||
testClass.testSetArrayElementValueInLoop()
|
||||
testClass.testArrayElementGetAndUpdate()
|
||||
testClass.testArrayElementUpdate()
|
||||
testClass.testArrayElementUpdateAndGet()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class AtomicArrayTest {
|
||||
|
||||
fun testIntArray() {
|
||||
val A = AtomicArrayClass()
|
||||
check(A.intArr[0].compareAndSet(0, 3))
|
||||
check(A.intArr[1].value == 0)
|
||||
A.intArr[0].lazySet(5)
|
||||
check(A.intArr[0].value + A.intArr[1].value + A.intArr[2].value == 5)
|
||||
check(A.intArr[0].compareAndSet(5, 10))
|
||||
check(A.intArr[0].getAndDecrement() == 10)
|
||||
check(A.intArr[0].value == 9)
|
||||
A.intArr[2].value = 2
|
||||
check(A.intArr[2].value == 2)
|
||||
check(A.intArr[2].compareAndSet(2, 34))
|
||||
check(A.intArr[2].value == 34)
|
||||
}
|
||||
|
||||
|
||||
fun testLongArray() {
|
||||
val A = AtomicArrayClass()
|
||||
A.longArr[0].value = 2424920024888888848
|
||||
check(A.longArr[0].value == 2424920024888888848)
|
||||
A.longArr[0].lazySet(8424920024888888848)
|
||||
check(A.longArr[0].value == 8424920024888888848)
|
||||
val ac = A.longArr[0].value
|
||||
A.longArr[3].value = ac
|
||||
check(A.longArr[3].getAndSet(8924920024888888848) == 8424920024888888848)
|
||||
check(A.longArr[3].value == 8924920024888888848)
|
||||
val ac1 = A.longArr[3].value
|
||||
A.longArr[4].value = ac1
|
||||
check(A.longArr[4].incrementAndGet() == 8924920024888888849)
|
||||
check(A.longArr[4].value == 8924920024888888849)
|
||||
check(A.longArr[4].getAndDecrement() == 8924920024888888849)
|
||||
check(A.longArr[4].value == 8924920024888888848)
|
||||
A.longArr[4].value = 8924920024888888848
|
||||
check(A.longArr[4].getAndAdd(100000000000000000) == 8924920024888888848)
|
||||
val ac2 = A.longArr[4].value
|
||||
A.longArr[1].value = ac2
|
||||
check(A.longArr[1].value == 9024920024888888848)
|
||||
check(A.longArr[1].addAndGet(-9223372036854775807) == -198452011965886959)
|
||||
check(A.longArr[1].value == -198452011965886959)
|
||||
check(A.longArr[1].incrementAndGet() == -198452011965886958)
|
||||
check(A.longArr[1].value == -198452011965886958)
|
||||
check(A.longArr[1].decrementAndGet() == -198452011965886959)
|
||||
check(A.longArr[1].value == -198452011965886959)
|
||||
}
|
||||
|
||||
|
||||
fun testBooleanArray() {
|
||||
val A = AtomicArrayClass()
|
||||
check(!A.booleanArr[1].value)
|
||||
A.booleanArr[1].compareAndSet(false, true)
|
||||
A.booleanArr[0].lazySet(true)
|
||||
check(!A.booleanArr[2].getAndSet(true))
|
||||
check(A.booleanArr[0].value && A.booleanArr[1].value && A.booleanArr[2].value)
|
||||
A.booleanArr[0].value = false
|
||||
check(!A.booleanArr[0].value)
|
||||
}
|
||||
|
||||
fun testRefArray() {
|
||||
val A = AtomicArrayClass()
|
||||
val a2 = ARef(2)
|
||||
val a3 = ARef(3)
|
||||
A.refArr[0].value = a2
|
||||
check(A.refArr[0].value!!.n == 2)
|
||||
check(A.refArr[0].compareAndSet(a2, a3))
|
||||
check(A.refArr[0].value!!.n == 3)
|
||||
val r0 = A.refArr[0].value
|
||||
A.refArr[3].value = r0
|
||||
check(A.refArr[3].value!!.n == 3)
|
||||
val a = A.a.value
|
||||
check(A.refArr[3].compareAndSet(a3, a))
|
||||
}
|
||||
}
|
||||
|
||||
class AtomicArrayClass {
|
||||
val intArr = AtomicIntArray(10)
|
||||
val longArr = AtomicLongArray(10)
|
||||
val booleanArr = AtomicBooleanArray(10)
|
||||
val refArr = atomicArrayOfNulls<ARef>(10)
|
||||
val anyArr = atomicArrayOfNulls<Any?>(10)
|
||||
val a = atomic(ARef(8))
|
||||
}
|
||||
|
||||
data class ARef(val n: Int)
|
||||
|
||||
fun box(): String {
|
||||
val testClass = AtomicArrayTest()
|
||||
testClass.testIntArray()
|
||||
testClass.testLongArray()
|
||||
testClass.testBooleanArray()
|
||||
testClass.testRefArray()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class ExtensionsTest {
|
||||
val a = atomic(0)
|
||||
val l = atomic(0L)
|
||||
val s = atomic<String?>(null)
|
||||
val b = atomic(true)
|
||||
|
||||
fun testScopedFieldGetters() {
|
||||
check(a.value == 0)
|
||||
val update = 3
|
||||
a.lazySet(update)
|
||||
check(a.compareAndSet(update, 8))
|
||||
a.lazySet(1)
|
||||
check(a.value == 1)
|
||||
check(a.getAndSet(2) == 1)
|
||||
check(a.value == 2)
|
||||
check(a.getAndIncrement() == 2)
|
||||
check(a.value == 3)
|
||||
check(a.getAndDecrement() == 3)
|
||||
check(a.value == 2)
|
||||
check(a.getAndAdd(2) == 2)
|
||||
check(a.value == 4)
|
||||
check(a.addAndGet(3) == 7)
|
||||
check(a.value == 7)
|
||||
check(a.incrementAndGet() == 8)
|
||||
check(a.value == 8)
|
||||
check(a.decrementAndGet() == 7)
|
||||
check(a.value == 7)
|
||||
check(a.compareAndSet(7, 10))
|
||||
}
|
||||
|
||||
inline fun AtomicInt.intExtensionArithmetic() {
|
||||
value = 0
|
||||
check(value == 0)
|
||||
val update = 3
|
||||
lazySet(update)
|
||||
check(compareAndSet(update, 8))
|
||||
lazySet(1)
|
||||
check(value == 1)
|
||||
check(getAndSet(2) == 1)
|
||||
check(value == 2)
|
||||
check(getAndIncrement() == 2)
|
||||
check(value == 3)
|
||||
check(getAndDecrement() == 3)
|
||||
check(value == 2)
|
||||
check(getAndAdd(2) == 2)
|
||||
check(value == 4)
|
||||
check(addAndGet(3) == 7)
|
||||
check(value == 7)
|
||||
check(incrementAndGet() == 8)
|
||||
check(value == 8)
|
||||
check(decrementAndGet() == 7)
|
||||
check(value == 7)
|
||||
check(compareAndSet(7, 10))
|
||||
check(compareAndSet(value, 55))
|
||||
check(value == 55)
|
||||
}
|
||||
|
||||
inline fun AtomicLong.longExtensionArithmetic() {
|
||||
value = 2424920024888888848
|
||||
check(value == 2424920024888888848)
|
||||
lazySet(8424920024888888848)
|
||||
check(value == 8424920024888888848)
|
||||
check(getAndSet(8924920024888888848) == 8424920024888888848)
|
||||
check(value == 8924920024888888848)
|
||||
check(incrementAndGet() == 8924920024888888849) // fails
|
||||
check(value == 8924920024888888849)
|
||||
check(getAndDecrement() == 8924920024888888849)
|
||||
check(value == 8924920024888888848)
|
||||
check(getAndAdd(100000000000000000) == 8924920024888888848)
|
||||
check(value == 9024920024888888848)
|
||||
check(addAndGet(-9223372036854775807) == -198452011965886959)
|
||||
check(value == -198452011965886959)
|
||||
check(incrementAndGet() == -198452011965886958)
|
||||
check(value == -198452011965886958)
|
||||
check(decrementAndGet() == -198452011965886959)
|
||||
check(value == -198452011965886959)
|
||||
}
|
||||
|
||||
inline fun AtomicRef<String?>.refExtension() {
|
||||
value = "aaa"
|
||||
check(value == "aaa")
|
||||
lazySet("bb")
|
||||
check(value == "bb")
|
||||
check(getAndSet("ccc") == "bb")
|
||||
check(value == "ccc")
|
||||
}
|
||||
|
||||
inline fun AtomicBoolean.booleanExtensionArithmetic() {
|
||||
value = false
|
||||
check(!value)
|
||||
lazySet(true)
|
||||
check(value)
|
||||
check(getAndSet(true))
|
||||
check(compareAndSet(value, false))
|
||||
check(!value)
|
||||
}
|
||||
|
||||
fun testExtension() {
|
||||
a.intExtensionArithmetic()
|
||||
l.longExtensionArithmetic()
|
||||
s.refExtension()
|
||||
b.booleanExtensionArithmetic()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
val testClass = ExtensionsTest()
|
||||
testClass.testScopedFieldGetters()
|
||||
testClass.testExtension()
|
||||
return "OK"
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class IndexArrayElementGetterTest {
|
||||
private val clazz = AtomicArrayClass()
|
||||
|
||||
fun fib(a: Int): Int = if (a == 0 || a == 1) a else fib(a - 1) + fib(a - 2)
|
||||
|
||||
fun testIndexArrayElementGetting() {
|
||||
clazz.intArr[8].value = 3
|
||||
val i = fib(4)
|
||||
val j = fib(5)
|
||||
assertEquals(clazz.intArr[i + j].value, 3)
|
||||
assertEquals(clazz.intArr[fib(4) + fib(5)].value, 3)
|
||||
clazz.longArr[3].value = 100
|
||||
assertEquals(clazz.longArr[fib(6) - fib(5)].value, 100)
|
||||
assertEquals(clazz.longArr[(fib(6) + fib(4)) % 8].value, 100)
|
||||
assertEquals(clazz.longArr[(fib(6) + fib(4)) % 8].value, 100)
|
||||
assertEquals(clazz.longArr[(fib(4) + fib(5)) % fib(5)].value, 100)
|
||||
}
|
||||
|
||||
class AtomicArrayClass {
|
||||
val intArr = AtomicIntArray(10)
|
||||
val longArr = AtomicLongArray(10)
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = IndexArrayElementGetterTest()
|
||||
testClass.testIndexArrayElementGetting()
|
||||
return "OK"
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class InlineExtensionWithTypeParameterTest {
|
||||
abstract class Segment<S : Segment<S>>(val id: Int)
|
||||
class SemaphoreSegment(id: Int) : Segment<SemaphoreSegment>(id)
|
||||
|
||||
private inline fun <S : Segment<S>> AtomicRef<S>.foo(
|
||||
id: Int,
|
||||
startFrom: S
|
||||
) {
|
||||
startFrom.getSegmentId()
|
||||
}
|
||||
|
||||
private inline fun <S : Segment<S>> S.getSegmentId(): Int {
|
||||
var cur: S = this
|
||||
return cur.id
|
||||
}
|
||||
|
||||
fun testInlineExtensionWithTypeParameter() {
|
||||
val s = SemaphoreSegment(0)
|
||||
val sref = atomic(s)
|
||||
sref.foo(0, s)
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = InlineExtensionWithTypeParameterTest()
|
||||
testClass.testInlineExtensionWithTypeParameter()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class LockFreeIntBitsTest {
|
||||
fun testBasic() {
|
||||
val bs = LockFreeIntBits()
|
||||
check(!bs[0])
|
||||
check(bs.bitSet(0))
|
||||
check(bs[0])
|
||||
check(!bs.bitSet(0))
|
||||
|
||||
check(!bs[1])
|
||||
check(bs.bitSet(1))
|
||||
check(bs[1])
|
||||
check(!bs.bitSet(1))
|
||||
check(!bs.bitSet(0))
|
||||
|
||||
check(bs[0])
|
||||
check(bs.bitClear(0))
|
||||
check(!bs.bitClear(0))
|
||||
|
||||
check(bs[1])
|
||||
}
|
||||
}
|
||||
|
||||
class LockFreeIntBits {
|
||||
private val bits = atomic(0)
|
||||
|
||||
private fun Int.mask() = 1 shl this
|
||||
|
||||
operator fun get(index: Int): Boolean = bits.value and index.mask() != 0
|
||||
|
||||
// User-defined private inline function
|
||||
private inline fun bitUpdate(check: (Int) -> Boolean, upd: (Int) -> Int): Boolean {
|
||||
bits.update {
|
||||
if (check(it)) return false
|
||||
upd(it)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun bitSet(index: Int): Boolean {
|
||||
val mask = index.mask()
|
||||
return bitUpdate({ it and mask != 0 }, { it or mask })
|
||||
}
|
||||
|
||||
fun bitClear(index: Int): Boolean {
|
||||
val mask = index.mask()
|
||||
return bitUpdate({ it and mask == 0 }, { it and mask.inv() })
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = LockFreeIntBitsTest()
|
||||
testClass.testBasic()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class LockFreeLongCounterTest {
|
||||
private inline fun testWith(g: LockFreeLongCounter.() -> Long) {
|
||||
val c = LockFreeLongCounter()
|
||||
check(c.g() == 0L)
|
||||
check(c.increment() == 1L)
|
||||
check(c.g() == 1L)
|
||||
check(c.increment() == 2L)
|
||||
check(c.g() == 2L)
|
||||
}
|
||||
|
||||
fun testBasic() = testWith { get() }
|
||||
|
||||
fun testGetInner() = testWith { getInner() }
|
||||
|
||||
fun testAdd2() {
|
||||
val c = LockFreeLongCounter()
|
||||
c.add2()
|
||||
check(c.get() == 2L)
|
||||
c.add2()
|
||||
check(c.get() == 4L)
|
||||
}
|
||||
|
||||
fun testSetM2() {
|
||||
val c = LockFreeLongCounter()
|
||||
c.setM2()
|
||||
check(c.get() == -2L)
|
||||
}
|
||||
}
|
||||
|
||||
class LockFreeLongCounter {
|
||||
private val counter = atomic(0L)
|
||||
|
||||
fun get(): Long = counter.value
|
||||
|
||||
fun increment(): Long = counter.incrementAndGet()
|
||||
|
||||
fun add2() = counter.getAndAdd(2)
|
||||
|
||||
fun setM2() {
|
||||
counter.value = -2L // LDC instruction here
|
||||
}
|
||||
|
||||
fun getInner(): Long = Inner().getFromOuter()
|
||||
|
||||
// testing how an inner class can get access to it
|
||||
private inner class Inner {
|
||||
fun getFromOuter(): Long = counter.value
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = LockFreeLongCounterTest()
|
||||
testClass.testBasic()
|
||||
testClass.testAdd2()
|
||||
testClass.testSetM2()
|
||||
testClass.testGetInner()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class LockFreeQueueTest {
|
||||
fun testBasic() {
|
||||
val q = LockFreeQueue()
|
||||
check(q.dequeue() == -1)
|
||||
q.enqueue(42)
|
||||
check(q.dequeue() == 42)
|
||||
check(q.dequeue() == -1)
|
||||
q.enqueue(1)
|
||||
q.enqueue(2)
|
||||
check(q.dequeue() == 1)
|
||||
check(q.dequeue() == 2)
|
||||
check(q.dequeue() == -1)
|
||||
}
|
||||
}
|
||||
|
||||
// MS-queue
|
||||
public class LockFreeQueue {
|
||||
private val head = atomic(Node(0))
|
||||
private val tail = atomic(head.value)
|
||||
|
||||
private class Node(val value: Int) {
|
||||
val next = atomic<Node?>(null)
|
||||
}
|
||||
|
||||
public fun enqueue(value: Int) {
|
||||
val node = Node(value)
|
||||
tail.loop { curTail ->
|
||||
val curNext = curTail.next.value
|
||||
if (curNext != null) {
|
||||
tail.compareAndSet(curTail, curNext)
|
||||
return@loop
|
||||
}
|
||||
if (curTail.next.compareAndSet(null, node)) {
|
||||
tail.compareAndSet(curTail, node)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun dequeue(): Int {
|
||||
head.loop { curHead ->
|
||||
val next = curHead.next.value ?: return -1
|
||||
if (head.compareAndSet(curHead, next)) return next.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = LockFreeQueueTest()
|
||||
testClass.testBasic()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class LockFreeStackTest {
|
||||
|
||||
fun testClear() {
|
||||
val s = LockFreeStack<String>()
|
||||
check(s.isEmpty())
|
||||
s.pushLoop("A")
|
||||
check(!s.isEmpty())
|
||||
s.clear()
|
||||
check(s.isEmpty())
|
||||
}
|
||||
|
||||
fun testPushPopLoop() {
|
||||
val s = LockFreeStack<String>()
|
||||
check(s.isEmpty())
|
||||
s.pushLoop("A")
|
||||
check(!s.isEmpty())
|
||||
check(s.popLoop() == "A")
|
||||
check(s.isEmpty())
|
||||
}
|
||||
|
||||
fun testPushPopUpdate() {
|
||||
val s = LockFreeStack<String>()
|
||||
check(s.isEmpty())
|
||||
s.pushUpdate("A")
|
||||
check(!s.isEmpty())
|
||||
check(s.popUpdate() == "A")
|
||||
check(s.isEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
class LockFreeStack<T> {
|
||||
private val top = atomic<Node<T>?>(null)
|
||||
|
||||
private class Node<T>(val value: T, val next: Node<T>?)
|
||||
|
||||
fun isEmpty() = top.value == null
|
||||
|
||||
fun clear() { top.value = null }
|
||||
|
||||
fun pushLoop(value: T) {
|
||||
top.loop { cur ->
|
||||
val upd = Node(value, cur)
|
||||
if (top.compareAndSet(cur, upd)) return
|
||||
}
|
||||
}
|
||||
|
||||
fun popLoop(): T? {
|
||||
top.loop { cur ->
|
||||
if (cur == null) return null
|
||||
if (top.compareAndSet(cur, cur.next)) return cur.value
|
||||
}
|
||||
}
|
||||
|
||||
fun pushUpdate(value: T) {
|
||||
top.update { cur -> Node(value, cur) }
|
||||
}
|
||||
|
||||
fun popUpdate(): T? =
|
||||
top.getAndUpdate { cur -> cur?.next } ?.value
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = LockFreeStackTest()
|
||||
testClass.testClear()
|
||||
testClass.testPushPopLoop()
|
||||
testClass.testPushPopUpdate()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class LockTest {
|
||||
private val inProgressLock = atomic(false)
|
||||
|
||||
fun testLock() {
|
||||
var result = ""
|
||||
if (inProgressLock.tryAcquire()) {
|
||||
result = "OK"
|
||||
}
|
||||
assertEquals("OK", result)
|
||||
}
|
||||
}
|
||||
|
||||
// This function will be removed by transformer
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun AtomicBoolean.tryAcquire(): Boolean = compareAndSet(false, true)
|
||||
|
||||
// This function is here to test if the Kotlin metadata still consistent after transform
|
||||
// It is used in ReflectionTest, DO NOT REMOVE
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun <AA, BB : Number> String.reflectionTest(mapParam: Map<in AA, BB>): List<BB> = error("no impl")
|
||||
|
||||
fun box(): String {
|
||||
val testClass = LockTest()
|
||||
testClass.testLock()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class LoopTest {
|
||||
private val a = atomic(0)
|
||||
private val r = atomic<A>(A("aaaa"))
|
||||
private val rs = atomic<String>("bbbb")
|
||||
|
||||
private class A(val s: String)
|
||||
|
||||
private inline fun casLoop(to: Int): Int {
|
||||
a.loop { cur ->
|
||||
if (a.compareAndSet(cur, to)) return a.value
|
||||
return 777
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun casLoopExpression(to: Int): Int = a.loop { cur ->
|
||||
if (a.compareAndSet(cur, to)) return a.value
|
||||
return 777
|
||||
}
|
||||
|
||||
private inline fun AtomicInt.extensionLoop(to: Int): Int {
|
||||
loop { cur ->
|
||||
if (compareAndSet(cur, to)) return value
|
||||
return 777
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun AtomicInt.extensionLoopExpression(to: Int): Int = loop { cur ->
|
||||
lazySet(cur + 10)
|
||||
return if (compareAndSet(cur, to)) value else incrementAndGet()
|
||||
}
|
||||
|
||||
private inline fun AtomicInt.extensionLoopMixedReceivers(first: Int, second: Int): Int {
|
||||
loop { cur ->
|
||||
compareAndSet(cur, first)
|
||||
a.compareAndSet(first, second)
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun AtomicInt.extensionLoopRecursive(to: Int): Int {
|
||||
loop { cur ->
|
||||
compareAndSet(cur, to)
|
||||
a.extensionLoop(5)
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
fun testIntExtensionLoops() {
|
||||
assertEquals(5, casLoop(5))
|
||||
assertEquals(6, casLoopExpression(6))
|
||||
assertEquals(66, a.extensionLoop(66))
|
||||
assertEquals(77, a.extensionLoopExpression(777))
|
||||
assertEquals(99, a.extensionLoopMixedReceivers(88, 99))
|
||||
assertEquals(5, a.extensionLoopRecursive(100))
|
||||
}
|
||||
|
||||
private inline fun AtomicRef<A>.casLoop(to: String): String = loop { cur ->
|
||||
if (compareAndSet(cur, A(to))) {
|
||||
val res = value.s
|
||||
return "${res}_AtomicRef<A>"
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun AtomicRef<String>.casLoop(to: String): String = loop { cur ->
|
||||
if (compareAndSet(cur, to)) return "${value}_AtomicRef<String>"
|
||||
}
|
||||
|
||||
fun testDeclarationWithEqualNames() {
|
||||
check(r.casLoop("kk") == "kk_AtomicRef<A>")
|
||||
check(rs.casLoop("pp") == "pp_AtomicRef<String>")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = LoopTest()
|
||||
testClass.testIntExtensionLoops()
|
||||
testClass.testDeclarationWithEqualNames()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class MultiInitTest {
|
||||
fun testBasic() {
|
||||
val t = MultiInit()
|
||||
check(t.incA() == 1)
|
||||
check(t.incA() == 2)
|
||||
check(t.incB() == 1)
|
||||
check(t.incB() == 2)
|
||||
}
|
||||
}
|
||||
|
||||
class MultiInit {
|
||||
private val a = atomic(0)
|
||||
private val b = atomic(0)
|
||||
|
||||
fun incA() = a.incrementAndGet()
|
||||
fun incB() = b.incrementAndGet()
|
||||
|
||||
companion object {
|
||||
fun foo() {} // just to force some clinit in outer file
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = MultiInitTest()
|
||||
testClass.testBasic()
|
||||
return "OK"
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class ParameterizedInlineFunExtensionTest {
|
||||
|
||||
private inline fun <S> AtomicRef<S>.foo(res1: S, res2: S, foo: (S) -> S): S {
|
||||
val res = bar(res1, res2)
|
||||
return res
|
||||
}
|
||||
|
||||
private inline fun <S> AtomicRef<S>.bar(res1: S, res2: S): S {
|
||||
return res2
|
||||
}
|
||||
|
||||
private val tail = atomic("aaa")
|
||||
|
||||
fun testClose() {
|
||||
val res = tail.foo("bbb", "ccc") { s -> s }
|
||||
assertEquals("ccc", res)
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = ParameterizedInlineFunExtensionTest()
|
||||
testClass.testClose()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlinx.atomicfu.locks.*
|
||||
import kotlin.test.*
|
||||
|
||||
class PropertyDeclarationTest {
|
||||
private val a: AtomicInt
|
||||
private val head: AtomicRef<String>
|
||||
private val lateIntArr: AtomicIntArray
|
||||
private val lateRefArr: AtomicArray<String?>
|
||||
private val lock: ReentrantLock
|
||||
|
||||
init {
|
||||
a = atomic(0)
|
||||
head = atomic("AAA")
|
||||
lateIntArr = AtomicIntArray(55)
|
||||
lateRefArr = atomicArrayOfNulls<String?>(10)
|
||||
lock = reentrantLock()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
assertEquals(0, a.value)
|
||||
check(head.compareAndSet("AAA", "BBB"))
|
||||
assertEquals("BBB", head.value)
|
||||
assertEquals(0, lateIntArr[35].value)
|
||||
assertEquals(null, lateRefArr[5].value)
|
||||
assertEquals(null, lock)
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = PropertyDeclarationTest()
|
||||
testClass.test()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import kotlinx.atomicfu.locks.*
|
||||
import kotlin.test.*
|
||||
|
||||
class ReentrantLockTest {
|
||||
private val lock = reentrantLock()
|
||||
private var state = 0
|
||||
|
||||
fun testLockField() {
|
||||
lock.withLock {
|
||||
state = 1
|
||||
}
|
||||
assertEquals(1, state)
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = ReentrantLockTest()
|
||||
testClass.testLockField()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class AA(val value: Int) {
|
||||
val b = B(value + 1)
|
||||
val c = C(D(E(value + 1)))
|
||||
|
||||
fun updateToB(affected: Any): Boolean {
|
||||
(affected as AtomicState).state.compareAndSet(this, b)
|
||||
return (affected.state.value is B && (affected.state.value as B).value == value + 1)
|
||||
}
|
||||
|
||||
fun manyProperties(affected: Any): Boolean {
|
||||
(affected as AtomicState).state.compareAndSet(this, c.d.e)
|
||||
return (affected.state.value is E && (affected.state.value as E).x == value + 1)
|
||||
}
|
||||
}
|
||||
|
||||
class B (val value: Int)
|
||||
|
||||
class C (val d: D)
|
||||
class D (val e: E)
|
||||
class E (val x: Int)
|
||||
|
||||
|
||||
class AtomicState(value: Any) {
|
||||
val state = atomic<Any?>(value)
|
||||
}
|
||||
|
||||
class ScopeTest {
|
||||
fun scopeTest() {
|
||||
val a = AA(0)
|
||||
val affected: Any = AtomicState(a)
|
||||
check(a.updateToB(affected))
|
||||
val a1 = AA(0)
|
||||
val affected1: Any = AtomicState(a1)
|
||||
check(a1.manyProperties(affected1))
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = ScopeTest()
|
||||
testClass.scopeTest()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
class SimpleLockTest {
|
||||
fun withLock() {
|
||||
val lock = SimpleLock()
|
||||
val result = lock.withLock {
|
||||
"OK"
|
||||
}
|
||||
assertEquals("OK", result)
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleLock {
|
||||
private val _locked = atomic(0)
|
||||
|
||||
fun <T> withLock(block: () -> T): T {
|
||||
// this contrieves construct triggers Kotlin compiler to reuse local variable slot #2 for
|
||||
// the exception in `finally` clause
|
||||
try {
|
||||
_locked.loop { locked ->
|
||||
check(locked == 0)
|
||||
if (!_locked.compareAndSet(0, 1)) return@loop // continue
|
||||
return block()
|
||||
}
|
||||
} finally {
|
||||
_locked.value = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = SimpleLockTest()
|
||||
testClass.withLock()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import kotlinx.atomicfu.locks.*
|
||||
import kotlin.test.*
|
||||
|
||||
class SynchronizedObjectTest : SynchronizedObject() {
|
||||
|
||||
fun testSync() {
|
||||
val result = synchronized(this) { bar() }
|
||||
assertEquals("OK", result)
|
||||
}
|
||||
|
||||
private fun bar(): String =
|
||||
synchronized(this) {
|
||||
"OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = SynchronizedObjectTest()
|
||||
testClass.testSync()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
private val a = atomic(0)
|
||||
private val b = atomic(2424920024888888848)
|
||||
private val c = atomic(true)
|
||||
private val abcNode = atomic(ANode(BNode(CNode(8))))
|
||||
private val any = atomic<Any?>(null)
|
||||
|
||||
private val intArr = AtomicIntArray(3)
|
||||
private val longArr = AtomicLongArray(5)
|
||||
private val booleanArr = AtomicBooleanArray(4)
|
||||
private val refArr = atomicArrayOfNulls<ANode<BNode<CNode>>>(5)
|
||||
private val anyRefArr = atomicArrayOfNulls<Any>(10)
|
||||
|
||||
private val stringAtomicNullArr = atomicArrayOfNulls<String>(10)
|
||||
|
||||
class TopLevelPrimitiveTest {
|
||||
|
||||
fun testTopLevelInt() {
|
||||
a.value
|
||||
check(a.value == 0)
|
||||
check(a.getAndSet(3) == 0)
|
||||
check(a.compareAndSet(3, 8))
|
||||
a.lazySet(1)
|
||||
check(a.value == 1)
|
||||
check(a.getAndSet(2) == 1)
|
||||
check(a.value == 2)
|
||||
check(a.getAndIncrement() == 2)
|
||||
check(a.value == 3)
|
||||
check(a.getAndDecrement() == 3)
|
||||
check(a.value == 2)
|
||||
check(a.getAndAdd(2) == 2)
|
||||
check(a.value == 4)
|
||||
check(a.addAndGet(3) == 7)
|
||||
check(a.value == 7)
|
||||
check(a.incrementAndGet() == 8)
|
||||
check(a.value == 8)
|
||||
check(a.decrementAndGet() == 7)
|
||||
check(a.value == 7)
|
||||
a.compareAndSet(7, 10)
|
||||
}
|
||||
|
||||
fun testTopLevelLong() {
|
||||
check(b.value == 2424920024888888848)
|
||||
b.lazySet(8424920024888888848)
|
||||
check(b.value == 8424920024888888848)
|
||||
check(b.getAndSet(8924920024888888848) == 8424920024888888848)
|
||||
check(b.value == 8924920024888888848)
|
||||
check(b.incrementAndGet() == 8924920024888888849)
|
||||
check(b.value == 8924920024888888849)
|
||||
check(b.getAndDecrement() == 8924920024888888849)
|
||||
check(b.value == 8924920024888888848)
|
||||
check(b.getAndAdd(100000000000000000) == 8924920024888888848)
|
||||
check(b.value == 9024920024888888848)
|
||||
check(b.addAndGet(-9223372036854775807) == -198452011965886959)
|
||||
check(b.value == -198452011965886959)
|
||||
check(b.incrementAndGet() == -198452011965886958)
|
||||
check(b.value == -198452011965886958)
|
||||
check(b.decrementAndGet() == -198452011965886959)
|
||||
check(b.value == -198452011965886959)
|
||||
}
|
||||
|
||||
fun testTopLevelBoolean() {
|
||||
check(c.value)
|
||||
c.lazySet(false)
|
||||
check(!c.value)
|
||||
check(!c.getAndSet(true))
|
||||
check(c.compareAndSet(true, false))
|
||||
check(!c.value)
|
||||
}
|
||||
|
||||
fun testTopLevelRef() {
|
||||
check(abcNode.value.b.c.d == 8)
|
||||
val newNode = ANode(BNode(CNode(76)))
|
||||
check(abcNode.getAndSet(newNode).b.c.d == 8)
|
||||
check(abcNode.value.b.c.d == 76)
|
||||
val l = IntArray(4){i -> i}
|
||||
any.lazySet(l)
|
||||
check((any.value as IntArray)[2] == 2)
|
||||
}
|
||||
|
||||
fun testTopLevelArrayOfNulls() {
|
||||
check(stringAtomicNullArr[0].value == null)
|
||||
check(stringAtomicNullArr[0].compareAndSet(null, "aa"))
|
||||
stringAtomicNullArr[1].lazySet("aa")
|
||||
check(stringAtomicNullArr[0].value == stringAtomicNullArr[1].value)
|
||||
}
|
||||
}
|
||||
|
||||
class TopLevelArrayTest {
|
||||
|
||||
fun testIntArray() {
|
||||
check(intArr[0].compareAndSet(0, 3))
|
||||
check(intArr[1].value == 0)
|
||||
intArr[0].lazySet(5)
|
||||
check(intArr[0].value + intArr[1].value + intArr[2].value == 5)
|
||||
check(intArr[0].compareAndSet(5, 10))
|
||||
check(intArr[0].getAndDecrement() == 10)
|
||||
check(intArr[0].value == 9)
|
||||
intArr[2].value = 2
|
||||
check(intArr[2].value == 2)
|
||||
check(intArr[2].compareAndSet(2, 34))
|
||||
check(intArr[2].value == 34)
|
||||
}
|
||||
|
||||
fun testLongArray() {
|
||||
longArr[0].value = 2424920024888888848
|
||||
check(longArr[0].value == 2424920024888888848)
|
||||
longArr[0].lazySet(8424920024888888848)
|
||||
check(longArr[0].value == 8424920024888888848)
|
||||
val ac = longArr[0].value
|
||||
longArr[3].value = ac
|
||||
check(longArr[3].getAndSet(8924920024888888848) == 8424920024888888848)
|
||||
check(longArr[3].value == 8924920024888888848)
|
||||
val ac1 = longArr[3].value
|
||||
longArr[4].value = ac1
|
||||
check(longArr[4].incrementAndGet() == 8924920024888888849)
|
||||
check(longArr[4].value == 8924920024888888849)
|
||||
check(longArr[4].getAndDecrement() == 8924920024888888849)
|
||||
check(longArr[4].value == 8924920024888888848)
|
||||
longArr[4].value = 8924920024888888848
|
||||
check(longArr[4].getAndAdd(100000000000000000) == 8924920024888888848)
|
||||
val ac2 = longArr[4].value
|
||||
longArr[1].value = ac2
|
||||
check(longArr[1].value == 9024920024888888848)
|
||||
check(longArr[1].addAndGet(-9223372036854775807) == -198452011965886959)
|
||||
check(longArr[1].value == -198452011965886959)
|
||||
check(longArr[1].incrementAndGet() == -198452011965886958)
|
||||
check(longArr[1].value == -198452011965886958)
|
||||
check(longArr[1].decrementAndGet() == -198452011965886959)
|
||||
check(longArr[1].value == -198452011965886959)
|
||||
}
|
||||
|
||||
fun testBooleanArray() {
|
||||
check(!booleanArr[1].value)
|
||||
booleanArr[1].compareAndSet(false, true)
|
||||
booleanArr[0].lazySet(true)
|
||||
check(!booleanArr[2].getAndSet(true))
|
||||
check(booleanArr[0].value && booleanArr[1].value && booleanArr[2].value)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun testRefArray() {
|
||||
val a2 = ANode(BNode(CNode(2)))
|
||||
val a3 = ANode(BNode(CNode(3)))
|
||||
refArr[0].value = a2
|
||||
check(refArr[0].value!!.b.c.d == 2)
|
||||
check(refArr[0].compareAndSet(a2, a3))
|
||||
check(refArr[0].value!!.b.c.d == 3)
|
||||
val r0 = refArr[0].value
|
||||
refArr[3].value = r0
|
||||
check(refArr[3].value!!.b.c.d == 3)
|
||||
val a = abcNode.value
|
||||
check(refArr[3].compareAndSet(a3, a))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class ANode<T>(val b: T)
|
||||
data class BNode<T>(val c: T)
|
||||
data class CNode(val d: Int)
|
||||
|
||||
fun box(): String {
|
||||
val primitiveTest = TopLevelPrimitiveTest()
|
||||
primitiveTest.testTopLevelInt()
|
||||
primitiveTest.testTopLevelLong()
|
||||
primitiveTest.testTopLevelBoolean()
|
||||
primitiveTest.testTopLevelRef()
|
||||
primitiveTest.testTopLevelArrayOfNulls()
|
||||
|
||||
val arrayTest = TopLevelArrayTest()
|
||||
arrayTest.testIntArray()
|
||||
arrayTest.testLongArray()
|
||||
arrayTest.testBooleanArray()
|
||||
arrayTest.testRefArray()
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import kotlinx.atomicfu.*
|
||||
import kotlin.test.*
|
||||
|
||||
private val topLevelS = atomic<Any>(arrayOf("A", "B"))
|
||||
|
||||
class UncheckedCastTest {
|
||||
private val s = atomic<Any>("AAA")
|
||||
private val bs = atomic<Any?>(null)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun testAtomicValUncheckedCast() {
|
||||
assertEquals((s as AtomicRef<String>).value, "AAA")
|
||||
bs.lazySet(arrayOf(arrayOf(Box(1), Box(2))))
|
||||
assertEquals((bs as AtomicRef<Array<Array<Box>>>).value[0]!![0].b * 10, 10)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun testTopLevelValUnchekedCast() {
|
||||
assertEquals((topLevelS as AtomicRef<Array<String>>).value[1], "B")
|
||||
}
|
||||
|
||||
private data class Box(val b: Int)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
|
||||
private inline fun <T> AtomicRef<T>.getString(): String =
|
||||
(this as AtomicRef<String>).value
|
||||
|
||||
fun testInlineFunc() {
|
||||
assertEquals("AAA", s.getString())
|
||||
}
|
||||
|
||||
private val a = atomicArrayOfNulls<Any?>(10)
|
||||
|
||||
fun testArrayValueUncheckedCast() {
|
||||
a[0].value = "OK"
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
assertEquals("OK", (a[0] as AtomicRef<String>).value)
|
||||
}
|
||||
|
||||
fun testArrayValueUncheckedCastInlineFunc() {
|
||||
a[0].value = "OK"
|
||||
assertEquals("OK", a[0].getString())
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val testClass = UncheckedCastTest()
|
||||
testClass.testTopLevelValUnchekedCast()
|
||||
testClass.testArrayValueUncheckedCast()
|
||||
testClass.testArrayValueUncheckedCastInlineFunc()
|
||||
testClass.testAtomicValUncheckedCast()
|
||||
testClass.testInlineFunc()
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user