1 package kotlinx.coroutines.internal
2 
3 import java.util.concurrent.atomic.*
4 
5 /**
6  * Atomic array with lock-free reads and synchronized modifications. It logically has an unbounded size,
7  * is implicitly filled with nulls, and is resized on updates as needed to grow.
8  */
9 internal class ResizableAtomicArray<T>(initialLength: Int) {
10     @Volatile
11     private var array = AtomicReferenceArray<T>(initialLength)
12 
13     // for debug output
currentLengthnull14     public fun currentLength(): Int = array.length()
15 
16     public operator fun get(index: Int): T? {
17         val array = this.array // volatile read
18         return if (index < array.length()) array[index] else null
19     }
20 
21     // Must not be called concurrently, e.g. always use synchronized(this) to call this function
setSynchronizednull22     fun setSynchronized(index: Int, value: T?) {
23         val curArray = this.array
24         val curLen = curArray.length()
25         if (index < curLen) {
26             curArray[index] = value
27             return
28         }
29         // It would be nice to copy array in batch instead of 1 by 1, but it seems like Java has no API for that
30         val newArray = AtomicReferenceArray<T>((index + 1).coerceAtLeast(2 * curLen))
31         for (i in 0 until curLen) newArray[i] = curArray[i]
32         newArray[index] = value
33         array = newArray // copy done
34     }
35 }
36