blob: de5d49112125470f97204dd83f47d8b81a7eddf7 [file] [log] [blame]
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("unused", "NO_EXPLICIT_RETURN_TYPE_IN_API_MODE", "NO_EXPLICIT_VISIBILITY_IN_API_MODE")
package kotlinx.coroutines.internal
import kotlinx.coroutines.*
private typealias Node = LinkedListNode
/** @suppress **This is unstable API and it is subject to change.** */
@Suppress("NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS") // :TODO: Remove when fixed: https://youtrack.jetbrains.com/issue/KT-23703
public actual typealias LockFreeLinkedListNode = LinkedListNode
/** @suppress **This is unstable API and it is subject to change.** */
public actual typealias LockFreeLinkedListHead = LinkedListHead
/** @suppress **This is unstable API and it is subject to change.** */
public open class LinkedListNode : DisposableHandle {
@PublishedApi internal var _next = this
@PublishedApi internal var _prev = this
@PublishedApi internal var _removed: Boolean = false
public inline val nextNode get() = _next
public inline val prevNode get() = _prev
public inline val isRemoved get() = _removed
public fun addLast(node: Node) {
val prev = this._prev
node._next = this
node._prev = prev
prev._next = node
this._prev = node
}
/*
* Remove that is invoked as a virtual function with a
* potentially augmented behaviour.
* I.g. `LockFreeLinkedListHead` throws, while `SendElementWithUndeliveredHandler`
* invokes handler on remove
*/
public open fun remove(): Boolean {
return removeImpl()
}
override fun dispose() {
remove()
}
@PublishedApi
internal fun removeImpl(): Boolean {
if (_removed) return false
val prev = this._prev
val next = this._next
prev._next = next
next._prev = prev
_removed = true
return true
}
public fun addOneIfEmpty(node: Node): Boolean {
if (_next !== this) return false
addLast(node)
return true
}
public inline fun addLastIf(node: Node, crossinline condition: () -> Boolean): Boolean {
if (!condition()) return false
addLast(node)
return true
}
public inline fun addLastIfPrev(node: Node, predicate: (Node) -> Boolean): Boolean {
if (!predicate(_prev)) return false
addLast(node)
return true
}
public inline fun addLastIfPrevAndIf(
node: Node,
predicate: (Node) -> Boolean, // prev node predicate
crossinline condition: () -> Boolean // atomically checked condition
): Boolean {
if (!predicate(_prev)) return false
if (!condition()) return false
addLast(node)
return true
}
public fun helpRemove() {} // No concurrency on JS -> no removal
public fun removeFirstOrNull(): Node? {
val next = _next
if (next === this) return null
check(next.removeImpl()) { "Should remove" }
return next
}
}
/** @suppress **This is unstable API and it is subject to change.** */
public open class LinkedListHead : LinkedListNode() {
public val isEmpty get() = _next === this
/**
* Iterates over all elements in this list of a specified type.
*/
public inline fun <reified T : Node> forEach(block: (T) -> Unit) {
var cur: Node = _next
while (cur != this) {
if (cur is T) block(cur)
cur = cur._next
}
}
// just a defensive programming -- makes sure that list head sentinel is never removed
public final override fun remove(): Nothing = throw UnsupportedOperationException()
}