shchuko

dynamic_arr

Dec 25th, 2021 (edited)
335
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 5.30 KB | None | 0 0
  1. import kotlinx.atomicfu.*
  2.  
  3. class DynamicArrayImpl<E> : DynamicArray<E> {
  4.     interface Node<E> {
  5.         interface WithValue<E> : Node<E> {
  6.             val value: E
  7.         }
  8.  
  9.         class Normal<E>(override val value: E) : WithValue<E>
  10.         class CopyInProgress<E>(override val value: E) : WithValue<E>
  11.         class CopyComplete<E>() : Node<E>
  12.     }
  13.  
  14.     private class Core<E>(val capacity: Int) {
  15.         val array = atomicArrayOfNulls<Node<E>>(capacity)
  16.         val next: AtomicRef<Core<E>?> = atomic(null)
  17.         val leftToCopy = atomic(capacity)
  18.  
  19.         fun getOrCreateNext(): Core<E> {
  20.             val oldValue = next.value
  21.             if (oldValue == null) {
  22.                 next.compareAndSet(null, Core(capacity * GROW_FACTOR))
  23.             }
  24.             // CAS should finish with success, in this or other thread
  25.             return next.value!!
  26.         }
  27.  
  28.     }
  29.  
  30.     companion object {
  31.         private const val GROW_FACTOR = 2
  32.         private const val INITIAL_CAPACITY = 1 // DO NOT CHANGE ME - OK, NOT CHANGED!
  33.     }
  34.  
  35.     private val core = atomic(Core<E>(INITIAL_CAPACITY))
  36.     private val sizeVal: AtomicInt = atomic(0)
  37.  
  38.     override fun get(index: Int): E {
  39.         require(0 <= index && index < sizeVal.value)
  40.         // Yes, we can return value from [Node.CopyInProgress],
  41.         // but let's help other threads to finish copy to new core operation
  42.         return doActionOnNormalNode(index) { _, node -> node.value }
  43.     }
  44.  
  45.     override fun put(index: Int, element: E) {
  46.         require(0 <= index && index < sizeVal.value)
  47.         doActionOnNormalNode(index) { core, normal ->
  48.             when (core.array[index].compareAndSet(normal, Node.Normal(element))) {
  49.                 true -> true // Stop retrying CAS - we're done
  50.                 false -> null // CAS failed, retry
  51.             }
  52.         }
  53.     }
  54.  
  55.     override fun pushBack(element: E) {
  56.         var currentCore = tryRemoveCopiedCores()
  57.         while (true) {
  58.             currentCore = skipCopiedCores(currentCore)
  59.             val currentSize = size
  60.  
  61.             if (currentSize >= currentCore.capacity) {
  62.                 currentCore = buildNextCore(currentCore)
  63.                 continue
  64.             }
  65.  
  66.             if (!currentCore.array[currentSize].compareAndSet(null, Node.Normal(element))) {
  67.                 continue
  68.             }
  69.             sizeVal.incrementAndGet()
  70.             return
  71.         }
  72.     }
  73.  
  74.     override val size: Int
  75.         get() = sizeVal.value
  76.  
  77.     private fun buildNextCore(fromCore: Core<E>): Core<E> {
  78.         val nextCore = fromCore.getOrCreateNext()
  79.  
  80.         // Copy elements to new core
  81.         for (i in 0 until fromCore.capacity) {
  82.             // Ignore nulls
  83.             var node = fromCore.array[i].value!!
  84.  
  85.             // Mark existing core values with "Copy in progress"
  86.             retryMarkAsInProgress@ while (node is Node.Normal) {
  87.                 if (fromCore.array[i].compareAndSet(node, Node.CopyInProgress(node.value))) {
  88.                     break@retryMarkAsInProgress
  89.                 }
  90.                 node = fromCore.array[i].value!!
  91.             }
  92.  
  93.             // Nothing to do if node already copied
  94.             if (node is Node.CopyComplete) {
  95.                 continue
  96.             }
  97.  
  98.             // If node is marked with "Copy in progress", try to copy it to new core
  99.             val value = (node as Node.WithValue).value
  100.             if (nextCore.array[i].value != null || nextCore.array[i].compareAndSet(null, Node.Normal(value))) {
  101.                 // If copy complete, we can release this node in old core
  102.                 fromCore.array[i].compareAndSet(node, Node.CopyComplete())
  103.                 fromCore.leftToCopy.decrementAndGet()
  104.             }
  105.         }
  106.  
  107.         return nextCore
  108.     }
  109.  
  110.     /**
  111.      * Retries to perform [action] on actual `Normal` node on [index],
  112.      * stops iterating when [action] retries non-null value.
  113.      * A short way to find node in the correct core and process it
  114.      */
  115.     private fun <R> doActionOnNormalNode(index: Int, action: (Core<E>, Node.Normal<E>) -> R?): R {
  116.         var currentCore = tryRemoveCopiedCores()
  117.  
  118.         while (true) {
  119.             currentCore = skipCopiedCores(currentCore)
  120.             if (index >= currentCore.capacity) {
  121.                 currentCore = currentCore.next.value!!
  122.                 continue
  123.             }
  124.  
  125.             val node = currentCore.array[index].value ?: continue
  126.             if (node is Node.Normal) {
  127.                 return action(currentCore, node) ?: continue
  128.             } else if (node is Node.CopyInProgress) {
  129.                 buildNextCore(currentCore)
  130.             } else {
  131.                 currentCore = currentCore.next.value!!
  132.             }
  133.         }
  134.     }
  135.  
  136.     private fun tryRemoveCopiedCores(): Core<E> {
  137.         var currentCore = core.value
  138.         while (currentCore.leftToCopy.value == 0) {
  139.             val nextNode = currentCore.next.value!!
  140.             if (!core.compareAndSet(currentCore, nextNode)) {
  141.                 return currentCore
  142.             }
  143.             currentCore = nextNode
  144.         }
  145.         return currentCore
  146.     }
  147.  
  148.     private fun skipCopiedCores(fromCore: Core<E>): Core<E> {
  149.         var temp = fromCore
  150.         while (temp.leftToCopy.value == 0) {
  151.             temp = temp.next.value!!
  152.         }
  153.         return temp
  154.     }
  155. }
  156.  
Add Comment
Please, Sign In to add comment