[K/N] Introduce atomic arrays in K/N stdlib

This commit introduces API for AtomicIntArray, AtomicLongArray and AtomicArray<T>.

The current set of functions is implemented via atomic arrays intrinsics (see KT-58360) and provides sequentially consistent memory ordering guarantees and no spurious failures in compareAndSet/compareAndExchange operations.

For details see: KT-60608

Merge-request: KT-MR-11071
Merged-by: Maria Sokolova <maria.sokolova@jetbrains.com>
This commit is contained in:
mvicsokolova
2023-07-21 15:30:20 +00:00
committed by Space Team
parent ebd43fc8c0
commit 298c4f8c32
4 changed files with 1206 additions and 2 deletions
@@ -1044,6 +1044,14 @@ standaloneTest("atomic1") {
source = "runtime/atomics/atomic1.kt"
}
tasks.register("atomicArraySmokeTest", KonanLocalTest) {
source = "runtime/atomics/atomic_array_smoke.kt"
}
tasks.register("atomicArrayStressTest", KonanLocalTest) {
source = "runtime/atomics/atomic_array_stress.kt"
}
tasks.register("lazy0", KonanLocalTest) {
useGoldenData = true
source = "runtime/workers/lazy0.kt"
@@ -0,0 +1,596 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:OptIn(kotlin.ExperimentalStdlibApi::class)
package runtime.atomics.atomic_array_smoke
import kotlin.test.*
import kotlin.concurrent.*
@Test
fun testAtomicIntArrayConstructor() {
val arr1 = AtomicIntArray(6)
assertEquals(arr1[4], 0)
assertEquals(arr1.length, 6)
val arr2 = AtomicIntArray(10) { i: Int -> i * 10 }
assertEquals(arr2[4], 40)
assertEquals(arr2.length, 10)
val emptyArr = AtomicIntArray(0)
assertEquals(emptyArr.length, 0)
assertFailsWith<IllegalArgumentException> {
val arrNegativeSize = AtomicIntArray(-5)
}
}
@Test
fun testAtomicIntArrayGetElement() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
for (i in 0 until atomicIntArr.length) {
assertEquals(i * 10, atomicIntArr[i], "testAtomicIntArrayGetElement: FAIL $i")
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr[22]
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr[-1]
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArraySetElement() {
val atomicIntArr = AtomicIntArray(10)
for (i in 0 until atomicIntArr.length) {
atomicIntArr[i] = i * 10
}
for (i in 0 until atomicIntArr.length) {
assertEquals(i * 10, atomicIntArr[i], "testAtomicIntArraySetElement: FAIL $i")
}
assertFailsWith<IndexOutOfBoundsException> {
atomicIntArr[22] = 100
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
atomicIntArr[-1] = 100
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArrayCompareAndExchange() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
val res1 = atomicIntArr.compareAndExchange(2, 20, 222) // success
assertTrue(res1 == 20 && atomicIntArr[2] == 222, "testAtomicIntArrayCompareAndExchange: FAIL 1")
val res2 = atomicIntArr.compareAndExchange(2, 222, 2222) // success
assertTrue(res2 == 222 && atomicIntArr[2] == 2222, "testAtomicIntArrayCompareAndExchange: FAIL 2")
val res3 = atomicIntArr.compareAndExchange(2, 223, 22222) // should fail
assertTrue(res3 == 2222 && atomicIntArr[2] == 2222, "testAtomicIntArrayCompareAndExchange: FAIL 3")
val res4 = atomicIntArr.compareAndExchange(9, 10, 999) // should fail
assertTrue(res4 == 90 && atomicIntArr[9] == 90, "testAtomicIntArrayCompareAndExchange: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.compareAndExchange(10, 33535, 39530)
}.let { ex ->
assertEquals("The index 10 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.compareAndExchange(-1, 33535, 39530)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArrayCompareAndSet() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
val res1 = atomicIntArr.compareAndSet(2, 20, 222) // success
assertTrue(res1 && atomicIntArr[2] == 222, "testAtomicIntArrayCompareAndSet: FAIL 1")
val res2 = atomicIntArr.compareAndSet(2, 222, 2222) // success
assertTrue(res2 && atomicIntArr[2] == 2222, "testAtomicIntArrayCompareAndSet: FAIL 2")
val res3 = atomicIntArr.compareAndSet(2, 223, 22222) // should fail
assertTrue(!res3 && atomicIntArr[2] == 2222, "testAtomicIntArrayCompareAndSet: FAIL 3")
val res4 = atomicIntArr.compareAndSet(9, 10, 999) // should fail
assertTrue(!res4 && atomicIntArr[9] == 90, "testAtomicIntArrayCompareAndSet: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.compareAndSet(10, 33535, 39530)
}.let { ex ->
assertEquals("The index 10 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.compareAndSet(-1, 33535, 39530)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArrayGetAndSet() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
assertEquals(20, atomicIntArr.getAndSet(2, 200), "testAtomicIntArrayGetAndSet: FAIL 1")
assertEquals(200, atomicIntArr.getAndSet(2, 2000), "testAtomicIntArrayGetAndSet: FAIL 2")
assertEquals(2000, atomicIntArr[2], "testAtomicIntArrayGetAndSet: FAIL 3")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.getAndSet(22, 33535)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.getAndSet(-1, 33535)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArrayGetAndAdd() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
assertEquals(10, atomicIntArr.getAndAdd(1, 100), "testAtomicIntArrayGetAndAdd: FAIL 1")
assertEquals(110, atomicIntArr[1], "testAtomicIntArrayGetAndAdd: FAIL 2")
assertEquals(110, atomicIntArr.getAndAdd(1, -100), "testAtomicIntArrayGetAndAdd: FAIL 3")
assertEquals(10, atomicIntArr[1], "testAtomicIntArrayGetAndAdd: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.getAndAdd(22, 33535)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.getAndAdd(-1, 33535)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArrayAddAndGet() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
assertEquals(110, atomicIntArr.addAndGet(1, 100), "testAtomicIntArrayAddAndGet: FAIL 1")
assertEquals(110, atomicIntArr[1], "testAtomicIntArrayAddAndGet: FAIL 2")
assertEquals(10, atomicIntArr.addAndGet(1, -100), "testAtomicIntArrayAddAndGet: FAIL 3")
assertEquals(10, atomicIntArr[1], "testAtomicIntArrayAddAndGet: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.addAndGet(22, 33535)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.addAndGet(-1, 33535)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArrayGetAndIncrement() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
assertEquals(10, atomicIntArr.getAndIncrement(1), "testAtomicIntArrayGetAndIncrement: FAIL 1")
assertEquals(11, atomicIntArr[1], "testAtomicIntArrayGetAndIncrement: FAIL 2")
assertEquals(11, atomicIntArr.getAndIncrement(1), "testAtomicIntArrayGetAndIncrement: FAIL 3")
assertEquals(12, atomicIntArr[1], "testAtomicIntArrayGetAndIncrement: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.getAndIncrement(22)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.getAndIncrement(-1)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArrayIncrementAndGet() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
assertEquals(11, atomicIntArr.incrementAndGet(1), "testAtomicIntArrayIncrementAndGet: FAIL 1")
assertEquals(11, atomicIntArr[1], "testAtomicIntArrayIncrementAndGet: FAIL 2")
assertEquals(12, atomicIntArr.incrementAndGet(1), "testAtomicIntArrayIncrementAndGet: FAIL 3")
assertEquals(12, atomicIntArr[1], "testAtomicIntArrayIncrementAndGet: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.incrementAndGet(22)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.incrementAndGet(-1)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArrayGetAndDecrement() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
assertEquals(10, atomicIntArr.getAndDecrement(1), "testAtomicIntArrayGetAndDecrement: FAIL 1")
assertEquals(9, atomicIntArr[1], "testAtomicIntArrayGetAndDecrement: FAIL 2")
assertEquals(9, atomicIntArr.getAndDecrement(1), "testAtomicIntArrayGetAndDecrement: FAIL 3")
assertEquals(8, atomicIntArr[1], "testAtomicIntArrayGetAndDecrement: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.getAndDecrement(22)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.getAndDecrement(-1)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicIntArrayDecrementAndGet() {
val atomicIntArr = AtomicIntArray(10) { i: Int -> i * 10 }
assertEquals(9, atomicIntArr.decrementAndGet(1), "testAtomicIntArrayDecrementAndGet: FAIL 1")
assertEquals(9, atomicIntArr[1], "testAtomicIntArrayDecrementAndGet: FAIL 2")
assertEquals(8, atomicIntArr.decrementAndGet(1), "testAtomicIntArrayDecrementAndGet: FAIL 3")
assertEquals(8, atomicIntArr[1], "testAtomicIntArrayDecrementAndGet: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.decrementAndGet(22)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicIntArr.decrementAndGet(-1)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicIntArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayConstructor() {
val arr1 = AtomicLongArray(6)
assertEquals(arr1[4], 0L)
assertEquals(arr1.length, 6)
val arr2 = AtomicLongArray(10) { i: Int -> i * 10L }
assertEquals(arr2[4], 40L)
assertEquals(arr2.length, 10)
val emptyArr = AtomicLongArray(0)
assertEquals(emptyArr.length, 0)
assertFailsWith<IllegalArgumentException> {
val arrNegativeSize = AtomicLongArray(-5)
}
}
@Test
fun testAtomicLongArrayGetElement() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
for (i in 0 until atomicLongArr.length) {
assertEquals(i * 10L, atomicLongArr[i], "testAtomicLongArrayGetElement: FAIL $i")
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr[22]
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr[-1]
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArraySetElement() {
val atomicLongArr = AtomicLongArray(10)
for (i in 0 until atomicLongArr.length) {
atomicLongArr[i] = i * 10L
}
for (i in 0 until atomicLongArr.length) {
assertEquals(i * 10L, atomicLongArr[i], "testAtomicLongArraySetElement: FAIL $i")
}
assertFailsWith<IndexOutOfBoundsException> {
atomicLongArr[10] = 3998009
}.let { ex ->
assertEquals("The index 10 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
atomicLongArr[-1] = 3998009
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayCompareAndExchange() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
val res1 = atomicLongArr.compareAndExchange(2, 20L, 222L) // success
assertTrue(res1 == 20L && atomicLongArr[2] == 222L, "testAtomicLongArrayCompareAndExchange: FAIL 1")
val res2 = atomicLongArr.compareAndExchange(2, 222L, 2222L) // success
assertTrue(res2 == 222L && atomicLongArr[2] == 2222L, "testAtomicLongArrayCompareAndExchange: FAIL 2")
val res3 = atomicLongArr.compareAndExchange(2, 223L, 22222L) // should fail
assertTrue(res3 == 2222L && atomicLongArr[2] == 2222L, "testAtomicLongArrayCompareAndExchange: FAIL 3")
val res4 = atomicLongArr.compareAndExchange(9, 10L, 999L) // should fail
assertTrue(res4 == 90L && atomicLongArr[9] == 90L, "testAtomicLongArrayCompareAndExchange: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
atomicLongArr.compareAndExchange(10, 9353, 39058308)
}.let { ex ->
assertEquals("The index 10 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
atomicLongArr.compareAndExchange(-1, 9353, 39058308)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayCompareAndSet() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
val res1 = atomicLongArr.compareAndSet(2, 20L, 222L) // success
assertTrue(res1 && atomicLongArr[2] == 222L, "testAtomicLongArrayCompareAndSet: FAIL 1")
val res2 = atomicLongArr.compareAndSet(2, 222L, 2222L) // success
assertTrue(res2 && atomicLongArr[2] == 2222L, "testAtomicLongArrayCompareAndSet: FAIL 2")
val res3 = atomicLongArr.compareAndSet(2, 223L, 22222L) // should fail
assertTrue(!res3 && atomicLongArr[2] == 2222L, "testAtomicLongArrayCompareAndSet: FAIL 3")
val res4 = atomicLongArr.compareAndSet(9, 10L, 999L) // should fail
assertTrue(!res4 && atomicLongArr[9] == 90L, "testAtomicLongArrayCompareAndSet: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
atomicLongArr.compareAndSet(10, 9353, 39058308)
}.let { ex ->
assertEquals("The index 10 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
atomicLongArr.compareAndSet(-1, 9353, 39058308)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayGetAndSet() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
assertEquals(20L, atomicLongArr.getAndSet(2, 200L), "testAtomicLongArrayGetAndSet: FAIL 1")
assertEquals(200L, atomicLongArr.getAndSet(2, 2000L), "testAtomicLongArrayGetAndSet: FAIL 2")
assertEquals(2000L, atomicLongArr[2], "testAtomicLongArrayGetAndSet: FAIL 3")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.getAndSet(22, 9353)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.getAndSet(-1, 9353)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayGetAndAdd() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
assertEquals(10L, atomicLongArr.getAndAdd(1, 100L), "testAtomicLongArrayGetAndAdd: FAIL 1")
assertEquals(110L, atomicLongArr[1], "testAtomicLongArrayGetAndAdd: FAIL 2")
assertEquals(110L, atomicLongArr.getAndAdd(1, -100L), "testAtomicLongArrayGetAndAdd: FAIL 3")
assertEquals(10L, atomicLongArr[1], "testAtomicLongArrayGetAndAdd: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.getAndAdd(100, 9353)
}.let { ex ->
assertEquals("The index 100 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.getAndAdd(-1, 9353)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayAddAndGet() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
assertEquals(110L, atomicLongArr.addAndGet(1, 100L), "testAtomicLongArrayAddAndGet: FAIL 1")
assertEquals(110L, atomicLongArr[1], "testAtomicLongArrayAddAndGet: FAIL 2")
assertEquals(10L, atomicLongArr.addAndGet(1, -100L), "testAtomicLongArrayAddAndGet: FAIL 3")
assertEquals(10L, atomicLongArr[1], "testAtomicLongArrayAddAndGet: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.addAndGet(22, 33535)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.addAndGet(-1, 33535)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayGetAndIncrement() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
assertEquals(10L, atomicLongArr.getAndIncrement(1), "testAtomicLongArrayGetAndIncrement: FAIL 1")
assertEquals(11L, atomicLongArr[1], "testAtomicLongArrayGetAndIncrement: FAIL 2")
assertEquals(11L, atomicLongArr.getAndIncrement(1), "testAtomicLongArrayGetAndIncrement: FAIL 3")
assertEquals(12L, atomicLongArr[1], "testAtomicLongArrayGetAndIncrement: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.getAndIncrement(22)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.addAndGet(-1, 33535)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayIncrementAndGet() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
assertEquals(11L, atomicLongArr.incrementAndGet(1), "testAtomicLongArrayIncrementAndGet: FAIL 1")
assertEquals(11L, atomicLongArr[1], "testAtomicLongArrayIncrementAndGet: FAIL 2")
assertEquals(12L, atomicLongArr.incrementAndGet(1), "testAtomicLongArrayIncrementAndGet: FAIL 3")
assertEquals(12L, atomicLongArr[1], "testAtomicLongArrayIncrementAndGet: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.incrementAndGet(22)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.incrementAndGet(-1)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayGetAndDecrement() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
assertEquals(10L, atomicLongArr.getAndDecrement(1), "testAtomicLongArrayGetAndDecrement: FAIL 1")
assertEquals(9L, atomicLongArr[1], "testAtomicLongArrayGetAndDecrement: FAIL 2")
assertEquals(9L, atomicLongArr.getAndDecrement(1), "testAtomicLongArrayGetAndDecrement: FAIL 3")
assertEquals(8L, atomicLongArr[1], "testAtomicLongArrayGetAndDecrement: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.getAndDecrement(22)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.getAndDecrement(-1)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicLongArrayDecrementAndGet() {
val atomicLongArr = AtomicLongArray(10) { i: Int -> i * 10L }
assertEquals(9L, atomicLongArr.decrementAndGet(1), "testAtomicLongArrayDecrementAndGet: FAIL 1")
assertEquals(9L, atomicLongArr[1], "testAtomicLongArrayDecrementAndGet: FAIL 2")
assertEquals(8L, atomicLongArr.decrementAndGet(1), "testAtomicLongArrayDecrementAndGet: FAIL 3")
assertEquals(8L, atomicLongArr[1], "testAtomicLongArrayDecrementAndGet: FAIL 4")
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.decrementAndGet(22)
}.let { ex ->
assertEquals("The index 22 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = atomicLongArr.decrementAndGet(-1)
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicLongArray with size 10.", ex.message)
}
}
@Test
fun testAtomicArrayConstructor() {
val arr2 = AtomicArray<String?>(10) { null }
assertEquals(arr2[4], null)
assertEquals(arr2.length, 10)
val emptyArr = AtomicArray<String?>(0) { "aa" }
assertEquals(emptyArr.length, 0)
assertFailsWith<IllegalArgumentException> {
val arrNegativeSize = AtomicArray<String?>(-5) { "aa" }
}
}
@Test
fun testAtomicArrayGetElement() {
val refArr = AtomicArray<String?>(10) { i -> "a$i" }
for (i in 0 until refArr.length) {
assertEquals("a$i", refArr[i], "testAtomicArrayGetElement: FAIL $i")
}
assertFailsWith<IndexOutOfBoundsException> {
val res = refArr[100]
}.let { ex ->
assertEquals("The index 100 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
val res = refArr[-1]
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
}
@Test
fun testAtomicArraySetElement() {
val refArr = AtomicArray<String?>(10) { null }
for (i in 0 until refArr.length) {
refArr[i] = "a$i"
}
for (i in 0 until refArr.length) {
assertEquals("a$i", refArr[i], "testAtomicArraySetElement: FAIL $i")
}
assertFailsWith<IndexOutOfBoundsException> {
refArr[100] = "aaa"
}.let { ex ->
assertEquals("The index 100 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
refArr[-1] = "aaa"
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
}
@Test
fun testAtomicArrayCompareAndExchange() {
val refArr = AtomicArray<String?>(10) { null }
val newValue = "aaa"
val res1 = refArr.compareAndExchange(3, null, newValue)
assertTrue(res1 == null && refArr[3] == newValue, "testAtomicArrayCompareAndExchange: FAIL 1")
val res2 = refArr.compareAndExchange(3, newValue, "bbb")
assertTrue(res2 == newValue && refArr[3] == "bbb", "testAtomicArrayCompareAndExchange: FAIL 2")
val res3 = refArr.compareAndExchange(3, newValue, "ccc")
assertTrue(res3 == "bbb" && refArr[3] == "bbb", "testAtomicArrayCompareAndExchange: FAIL 3")
assertFailsWith<IndexOutOfBoundsException> {
refArr.compareAndExchange(10, "aaa", "jdndkj")
}.let { ex ->
assertEquals("The index 10 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
refArr.compareAndExchange(-1, "aaa", "jdndkj")
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
}
@Test
fun testAtomicArrayCompareAndSet() {
val refArr = AtomicArray<String?>(10) { null }
val newValue = "aaa"
val res1 = refArr.compareAndSet(3, null, newValue)
assertTrue(res1 && refArr[3] == newValue, "testAtomicArrayCompareAndSet: FAIL 1")
val res2 = refArr.compareAndSet(3, newValue, "bbb")
assertTrue(res2 && refArr[3] == "bbb", "testAtomicArrayCompareAndSet: FAIL 2")
val res3 = refArr.compareAndSet(3, newValue, "ccc")
assertTrue(!res3 && refArr[3] == "bbb", "testAtomicArrayCompareAndSet: FAIL 3")
assertFailsWith<IndexOutOfBoundsException> {
refArr.compareAndSet(10, "aaa", "jdndkj")
}.let { ex ->
assertEquals("The index 10 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
refArr.compareAndSet(-1, "aaa", "jdndkj")
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
}
@Test
fun testAtomicArrayGetAndSet() {
val refArr = AtomicArray<String?>(10) { null }
val res4 = refArr.getAndSet(4, "aaa")
assertEquals(null, res4, "testAtomicArrayGetAndSet: FAIL 1")
val res5 = refArr.getAndSet(4, "bbb")
assertEquals("aaa", res5, "testAtomicArrayGetAndSet: FAIL 2")
assertFailsWith<IndexOutOfBoundsException> {
refArr.getAndSet(10, "aaa")
}.let { ex ->
assertEquals("The index 10 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
assertFailsWith<IndexOutOfBoundsException> {
refArr.getAndSet(-1, "aaa")
}.let { ex ->
assertEquals("The index -1 is out of the bounds of the AtomicArray with size 10.", ex.message)
}
}
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:OptIn(kotlin.ExperimentalStdlibApi::class)
package runtime.atomics.atomic_array_stress
import kotlin.test.*
import kotlin.concurrent.*
import kotlin.native.concurrent.*
fun testAtomicIntArrayStress(workers: Array<Worker>) {
val intArr = AtomicIntArray(10)
val futures = Array(workers.size, { workerIndex ->
workers[workerIndex].execute(TransferMode.SAFE, { intArr }) { intArr ->
for (i in 0 until 500) {
val index = (0 until intArr.length).random()
intArr.incrementAndGet(index)
}
}
})
futures.forEach {
it.result
}
var sum = 0
for (i in 0 until intArr.length) {
sum += intArr[i]
}
assertEquals(workers.size * 500, sum)
}
fun testAtomicLongArrayStress(workers: Array<Worker>) {
val longArr = AtomicLongArray(10)
val futures = Array(workers.size, { workerIndex ->
workers[workerIndex].execute(TransferMode.SAFE, { longArr }) { longArr ->
for (i in 0 until 500) {
val index = (0 until longArr.length).random()
longArr.incrementAndGet(index)
}
}
})
futures.forEach {
it.result
}
var sum = 0L
for (i in 0 until longArr.length) {
sum += longArr[i]
}
assertEquals(workers.size.toLong() * 500, sum)
}
private class A(val n: Int)
fun testAtomicArrayStress(workers: Array<Worker>) {
val refArr = AtomicArray(10) { A(0) }
val futures = Array(workers.size, { workerIndex ->
workers[workerIndex].execute(TransferMode.SAFE, { refArr }) { refArr ->
for (i in 0 until 500) {
val index = (0 until refArr.length).random()
while(true) {
val cur = refArr[index]
val newValue = A(((cur as A).n + 1))
if (refArr.compareAndSet(index, cur, newValue)) break
}
}
}
})
futures.forEach {
it.result
}
var sum = 0
for (i in 0 until refArr.length) {
sum += (refArr[i] as A).n
}
assertEquals(workers.size * 500, sum)
}
@Test
fun runStressTest() {
val COUNT = 20
val workers = Array(COUNT, { _ -> Worker.start()})
testAtomicIntArrayStress(workers)
testAtomicLongArrayStress(workers)
testAtomicArrayStress(workers)
}
@@ -9,6 +9,519 @@ import kotlin.native.internal.*
import kotlin.reflect.*
import kotlin.concurrent.*
import kotlin.native.concurrent.*
import kotlin.internal.RequireKotlin
import kotlin.internal.RequireKotlinVersionKind
/**
* An [IntArray] in which elements are always updated atomically.
* For additional details about atomicity guarantees for reads and writes see [kotlin.concurrent.Volatile].
*/
@SinceKotlin("1.9")
@RequireKotlin(version = "1.9.20", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
@ExperimentalStdlibApi
public class AtomicIntArray {
private val array: IntArray
/**
* Creates a new [AtomicIntArray] of the given [size], with all elements initialized to zero.
*
* @throws RuntimeException if the specified [size] is negative.
*/
public constructor(size: Int) {
array = IntArray(size)
}
/**
* Creates a new [AtomicIntArray] filled with elements of the given [array].
*/
@PublishedApi
internal constructor(array: IntArray) {
this.array = array.copyOf()
}
/**
* Returns the number of elements in the array.
*/
public val length: Int get() = array.size
/**
* Atomically gets the value of the element at the given [index].
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public operator fun get(index: Int): Int {
checkBounds(index)
return array.atomicGet(index)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue].
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public operator fun set(index: Int, newValue: Int): Unit {
checkBounds(index)
array.atomicSet(index, newValue)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun getAndSet(index: Int, newValue: Int): Int {
checkBounds(index)
return array.getAndSet(index, newValue)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue].
* Returns true if the operation was successful and false only if the current value of the element was not equal to the expected value.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun compareAndSet(index: Int, expectedValue: Int, newValue: Int): Boolean {
checkBounds(index)
return array.compareAndSet(index, expectedValue, newValue)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue] and returns the old value of the element in any case.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun compareAndExchange(index: Int, expectedValue: Int, newValue: Int): Int {
checkBounds(index)
return array.compareAndExchange(index, expectedValue, newValue)
}
/**
* Atomically adds the given [delta] to the element at the given [index] and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun getAndAdd(index: Int, delta: Int): Int {
checkBounds(index)
return array.getAndAdd(index, delta)
}
/**
* Atomically adds the given [delta] to the element at the given [index] and returns the new value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun addAndGet(index: Int, delta: Int): Int {
checkBounds(index)
return array.getAndAdd(index, delta) + delta
}
/**
* Atomically increments the element at the given [index] by one and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun getAndIncrement(index: Int): Int {
checkBounds(index)
return array.getAndAdd(index, 1)
}
/**
* Atomically increments the element at the given [index] by one and returns the new value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun incrementAndGet(index: Int): Int {
checkBounds(index)
return array.getAndAdd(index, 1) + 1
}
/**
* Atomically decrements the element at the given [index] by one and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun getAndDecrement(index: Int): Int {
checkBounds(index)
return array.getAndAdd(index, -1)
}
/**
* Atomically decrements the element at the given [index] by one and returns the new value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun decrementAndGet(index: Int): Int {
checkBounds(index)
return array.getAndAdd(index, -1) - 1
}
/**
* Returns the string representation of the underlying [IntArray][array].
*/
public override fun toString(): String = array.toString()
private fun checkBounds(index: Int) {
if (index < 0 || index >= array.size) throw IndexOutOfBoundsException("The index $index is out of the bounds of the AtomicIntArray with size ${array.size}.")
}
}
/**
* Creates a new [AtomicIntArray] of the given [size], where each element is initialized by calling the given [init] function.
*
* The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an array element given its index.
*
* @throws RuntimeException if the specified [size] is negative.
*/
@SinceKotlin("1.9")
@RequireKotlin(version = "1.9.20", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
@ExperimentalStdlibApi
public inline fun AtomicIntArray(size: Int, init: (Int) -> Int): AtomicIntArray {
val inner = IntArray(size)
for (index in 0 until size) {
inner[index] = init(index)
}
return AtomicIntArray(inner)
}
/**
* An [LongArray] in which elements are always updated atomically.
* For additional details about atomicity guarantees for reads and writes see [kotlin.concurrent.Volatile].
*/
@SinceKotlin("1.9")
@RequireKotlin(version = "1.9.20", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
@ExperimentalStdlibApi
public class AtomicLongArray {
private val array: LongArray
/**
* Creates a new [AtomicLongArray] of the given [size], with all elements initialized to zero.
*
* @throws RuntimeException if the specified [size] is negative.
*/
public constructor(size: Int) {
array = LongArray(size)
}
/**
* Creates a new [AtomicLongArray] filled with elements of the given [array].
*/
@PublishedApi
internal constructor(array: LongArray) {
this.array = array.copyOf()
}
/**
* Returns the number of elements in the array.
*/
public val length: Int get() = array.size
/**
* Atomically gets the value of the element at the given [index].
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public operator fun get(index: Int): Long {
checkBounds(index)
return array.atomicGet(index)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue].
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public operator fun set(index: Int, newValue: Long): Unit {
checkBounds(index)
array.atomicSet(index, newValue)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun getAndSet(index: Int, newValue: Long): Long {
checkBounds(index)
return array.getAndSet(index, newValue)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue].
* Returns true if the operation was successful and false only if the current value of the element was not equal to the expected value.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun compareAndSet(index: Int, expectedValue: Long, newValue: Long): Boolean {
checkBounds(index)
return array.compareAndSet(index, expectedValue, newValue)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue] and returns the old value of the element in any case.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun compareAndExchange(index: Int, expectedValue: Long, newValue: Long): Long {
checkBounds(index)
return array.compareAndExchange(index, expectedValue, newValue)
}
/**
* Atomically adds the given [delta] to the element at the given [index] and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun getAndAdd(index: Int, delta: Long): Long {
checkBounds(index)
return array.getAndAdd(index, delta)
}
/**
* Atomically adds the given [delta] to the element at the given [index] and returns the new value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun addAndGet(index: Int, delta: Long): Long {
checkBounds(index)
return array.getAndAdd(index, delta) + delta
}
/**
* Atomically increments the element at the given [index] by one and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun getAndIncrement(index: Int): Long {
checkBounds(index)
return array.getAndAdd(index, 1L)
}
/**
* Atomically increments the element at the given [index] by one and returns the new value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun incrementAndGet(index: Int): Long {
checkBounds(index)
return array.getAndAdd(index, 1L) + 1L
}
/**
* Atomically decrements the element at the given [index] by one and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun getAndDecrement(index: Int): Long {
checkBounds(index)
return array.getAndAdd(index, -1L)
}
/**
* Atomically decrements the element at the given [index] by one and returns the new value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun decrementAndGet(index: Int): Long {
checkBounds(index)
return array.getAndAdd(index, -1L) - 1L
}
/**
* Returns the string representation of the underlying [IntArray][array].
*/
public override fun toString(): String = array.toString()
private fun checkBounds(index: Int) {
if (index < 0 || index >= array.size) throw IndexOutOfBoundsException("The index $index is out of the bounds of the AtomicLongArray with size ${array.size}.")
}
}
/**
* Creates a new [AtomicLongArray] of the given [size], where each element is initialized by calling the given [init] function.
*
* The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an array element given its index.
*
* @throws RuntimeException if the specified [size] is negative.
*/
@SinceKotlin("1.9")
@RequireKotlin(version = "1.9.20", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
@ExperimentalStdlibApi
public inline fun AtomicLongArray(size: Int, init: (Int) -> Long): AtomicLongArray {
val inner = LongArray(size)
for (index in 0 until size) {
inner[index] = init(index)
}
return AtomicLongArray(inner)
}
/**
* An [Array]<T> in which elements are always updated atomically.
* For additional details about atomicity guarantees for reads and writes see [kotlin.concurrent.Volatile].
*/
@SinceKotlin("1.9")
@RequireKotlin(version = "1.9.20", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
@ExperimentalStdlibApi
public class AtomicArray<T> {
private val array: Array<T>
/**
* Creates a new [AtomicArray]<T> filled with elements of the given [array].
*/
@PublishedApi
internal constructor(array: Array<T>) {
this.array = array.copyOf()
}
/**
* Returns the number of elements in the array.
*/
public val length: Int get() = array.size
/**
* Atomically gets the value of the element at the given [index].
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public operator fun get(index: Int): T {
checkBounds(index)
return array.atomicGet(index)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue].
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public operator fun set(index: Int, newValue: T): Unit {
checkBounds(index)
array.atomicSet(index, newValue)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun getAndSet(index: Int, newValue: T): T {
checkBounds(index)
return array.getAndSet(index, newValue)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue].
* Returns true if the operation was successful and false only if the current value of the element was not equal to the expected value.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun compareAndSet(index: Int, expectedValue: T, newValue: T): Boolean {
checkBounds(index)
return array.compareAndSet(index, expectedValue, newValue)
}
/**
* Atomically sets the value of the element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue] and returns the old value of the element in any case.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
public fun compareAndExchange(index: Int, expectedValue: T, newValue: T): T {
checkBounds(index)
return array.compareAndExchange(index, expectedValue, newValue)
}
/**
* Returns the string representation of the underlying [IntArray][array].
*/
public override fun toString(): String = array.toString()
private fun checkBounds(index: Int) {
if (index < 0 || index >= array.size) throw IndexOutOfBoundsException("The index $index is out of the bounds of the AtomicArray with size ${array.size}.")
}
}
/**
* Creates a new [AtomicArray]<T> of the given [size], where each element is initialized by calling the given [init] function.
*
* The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an array element given its index.
*
* @throws RuntimeException if the specified [size] is negative.
*/
@SinceKotlin("1.9")
@RequireKotlin(version = "1.9.20", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
@ExperimentalStdlibApi
@Suppress("UNCHECKED_CAST")
public inline fun <reified T> AtomicArray(size: Int, init: (Int) -> T): AtomicArray<T> {
val inner = arrayOfNulls<T>(size)
for (index in 0 until size) {
inner[index] = init(index)
}
return AtomicArray(inner as Array<T>)
}
/**
* Atomically gets the value of the [IntArray][this] element at the given [index].
@@ -42,7 +555,7 @@ internal external fun IntArray.atomicSet(index: Int, newValue: Int)
internal external fun IntArray.getAndSet(index: Int, newValue: Int): Int
/**
* Atomically adds the [given value][delta] to the [IntArray][this] element at the given [index]
* Atomically adds the given [delta] to the [IntArray][this] element at the given [index]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
@@ -107,7 +620,7 @@ internal external fun LongArray.atomicSet(index: Int, newValue: Long)
internal external fun LongArray.getAndSet(index: Int, newValue: Long): Long
/**
* Atomically adds the [given value][delta] to the [LongArray][this] element at the given [index]
* Atomically adds the given [delta] to the [LongArray][this] element at the given [index]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.