mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-08 09:47:09 +00:00
progress on test adaptation
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
package dev.inmo.micro_utils.coroutines.collections
|
package dev.inmo.micro_utils.coroutines.collections
|
||||||
|
|
||||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||||
import dev.inmo.micro_utils.coroutines.waitReadRelease
|
|
||||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||||
import kotlinx.coroutines.job
|
import kotlinx.coroutines.job
|
||||||
@@ -93,7 +92,7 @@ class SortedBinaryTreeNode<T>(
|
|||||||
* This process will continue until function will not find place to put [SortedBinaryTreeNode] with data or
|
* This process will continue until function will not find place to put [SortedBinaryTreeNode] with data or
|
||||||
* [SortedBinaryTreeNode] with [SortedBinaryTreeNode.data] same as [newData] will be found
|
* [SortedBinaryTreeNode] with [SortedBinaryTreeNode.data] same as [newData] will be found
|
||||||
*/
|
*/
|
||||||
private suspend fun <T> SortedBinaryTreeNode<T>.addSubNode(
|
private suspend fun <T> SortedBinaryTreeNode<T>.upsertSubNode(
|
||||||
subNode: SortedBinaryTreeNode<T>,
|
subNode: SortedBinaryTreeNode<T>,
|
||||||
skipLockers: Set<SmartRWLocker> = emptySet()
|
skipLockers: Set<SmartRWLocker> = emptySet()
|
||||||
): SortedBinaryTreeNode<T> {
|
): SortedBinaryTreeNode<T> {
|
||||||
@@ -149,7 +148,7 @@ private suspend fun <T> SortedBinaryTreeNode<T>.addSubNode(
|
|||||||
* [SortedBinaryTreeNode] with [SortedBinaryTreeNode.data] same as [newData] will be found
|
* [SortedBinaryTreeNode] with [SortedBinaryTreeNode.data] same as [newData] will be found
|
||||||
*/
|
*/
|
||||||
suspend fun <T> SortedBinaryTreeNode<T>.addSubNode(newData: T): SortedBinaryTreeNode<T> {
|
suspend fun <T> SortedBinaryTreeNode<T>.addSubNode(newData: T): SortedBinaryTreeNode<T> {
|
||||||
return addSubNode(
|
return upsertSubNode(
|
||||||
SortedBinaryTreeNode(newData, comparator)
|
SortedBinaryTreeNode(newData, comparator)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -198,8 +197,8 @@ suspend fun <T> SortedBinaryTreeNode<T>.findParentNode(data: T): SortedBinaryTre
|
|||||||
*/
|
*/
|
||||||
suspend fun <T> SortedBinaryTreeNode<T>.removeSubNode(data: T): Pair<SortedBinaryTreeNode<T>, SortedBinaryTreeNode<T>>? {
|
suspend fun <T> SortedBinaryTreeNode<T>.removeSubNode(data: T): Pair<SortedBinaryTreeNode<T>, SortedBinaryTreeNode<T>>? {
|
||||||
val onFoundToRemoveCallback: suspend SortedBinaryTreeNode<T>.(left: SortedBinaryTreeNode<T>?, right: SortedBinaryTreeNode<T>?) -> Unit = { left, right ->
|
val onFoundToRemoveCallback: suspend SortedBinaryTreeNode<T>.(left: SortedBinaryTreeNode<T>?, right: SortedBinaryTreeNode<T>?) -> Unit = { left, right ->
|
||||||
left ?.also { leftNode -> addSubNode(leftNode, setOf(locker)) }
|
left ?.also { leftNode -> upsertSubNode(leftNode, setOf(locker)) }
|
||||||
right ?.also { rightNode -> addSubNode(rightNode, setOf(locker)) }
|
right ?.also { rightNode -> upsertSubNode(rightNode, setOf(locker)) }
|
||||||
}
|
}
|
||||||
while (coroutineContext.job.isActive) {
|
while (coroutineContext.job.isActive) {
|
||||||
val foundParentNode = findParentNode(data) ?: return null
|
val foundParentNode = findParentNode(data) ?: return null
|
||||||
|
@@ -99,7 +99,7 @@ class SortedMapLikeBinaryTreeNode<K, V>(
|
|||||||
*
|
*
|
||||||
* @param replaceMode Will replace only value if node already exists
|
* @param replaceMode Will replace only value if node already exists
|
||||||
*/
|
*/
|
||||||
private suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.addSubNode(
|
private suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.upsertSubNode(
|
||||||
subNode: SortedMapLikeBinaryTreeNode<K, V>,
|
subNode: SortedMapLikeBinaryTreeNode<K, V>,
|
||||||
skipLockers: Set<SmartRWLocker> = emptySet(),
|
skipLockers: Set<SmartRWLocker> = emptySet(),
|
||||||
replaceMode: Boolean
|
replaceMode: Boolean
|
||||||
@@ -180,11 +180,11 @@ private suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.addSubNode(
|
|||||||
* This process will continue until function will not find place to put [SortedMapLikeBinaryTreeNode] with data or
|
* This process will continue until function will not find place to put [SortedMapLikeBinaryTreeNode] with data or
|
||||||
* [SortedMapLikeBinaryTreeNode] with [SortedMapLikeBinaryTreeNode.key] same as [key] will be found
|
* [SortedMapLikeBinaryTreeNode] with [SortedMapLikeBinaryTreeNode.key] same as [key] will be found
|
||||||
*/
|
*/
|
||||||
suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.addSubNode(
|
suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.upsertSubNode(
|
||||||
key: K,
|
key: K,
|
||||||
value: V
|
value: V
|
||||||
): SortedMapLikeBinaryTreeNode<K, V> {
|
): SortedMapLikeBinaryTreeNode<K, V> {
|
||||||
return addSubNode(
|
return upsertSubNode(
|
||||||
SortedMapLikeBinaryTreeNode(key, value, comparator),
|
SortedMapLikeBinaryTreeNode(key, value, comparator),
|
||||||
replaceMode = false
|
replaceMode = false
|
||||||
)
|
)
|
||||||
@@ -234,8 +234,8 @@ suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.findParentNode(data: K): So
|
|||||||
*/
|
*/
|
||||||
suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.removeSubNode(data: K): Pair<SortedMapLikeBinaryTreeNode<K, V>, SortedMapLikeBinaryTreeNode<K, V>>? {
|
suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.removeSubNode(data: K): Pair<SortedMapLikeBinaryTreeNode<K, V>, SortedMapLikeBinaryTreeNode<K, V>>? {
|
||||||
val onFoundToRemoveCallback: suspend SortedMapLikeBinaryTreeNode<K, V>.(left: SortedMapLikeBinaryTreeNode<K, V>?, right: SortedMapLikeBinaryTreeNode<K, V>?) -> Unit = { left, right ->
|
val onFoundToRemoveCallback: suspend SortedMapLikeBinaryTreeNode<K, V>.(left: SortedMapLikeBinaryTreeNode<K, V>?, right: SortedMapLikeBinaryTreeNode<K, V>?) -> Unit = { left, right ->
|
||||||
left ?.also { leftNode -> addSubNode(leftNode, setOf(locker), replaceMode = true) }
|
left ?.also { leftNode -> upsertSubNode(leftNode, setOf(locker), replaceMode = true) }
|
||||||
right ?.also { rightNode -> addSubNode(rightNode, setOf(locker), replaceMode = true) }
|
right ?.also { rightNode -> upsertSubNode(rightNode, setOf(locker), replaceMode = true) }
|
||||||
}
|
}
|
||||||
while (coroutineContext.job.isActive) {
|
while (coroutineContext.job.isActive) {
|
||||||
val foundParentNode = findParentNode(data) ?: return null
|
val foundParentNode = findParentNode(data) ?: return null
|
||||||
@@ -337,6 +337,52 @@ suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.findNodesInRange(from: K, t
|
|||||||
}
|
}
|
||||||
error("Unable to find nodes range")
|
error("Unable to find nodes range")
|
||||||
}
|
}
|
||||||
|
suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.deepEquals(other: SortedMapLikeBinaryTreeNode<K, V>): Boolean {
|
||||||
|
val leftToCheck = mutableSetOf(this)
|
||||||
|
val othersToCheck = mutableSetOf(other)
|
||||||
|
val lockedLockers = mutableSetOf<SmartRWLocker>()
|
||||||
|
try {
|
||||||
|
while (leftToCheck.isNotEmpty() && othersToCheck.isNotEmpty()) {
|
||||||
|
val thisToCheck = leftToCheck.first()
|
||||||
|
leftToCheck.remove(thisToCheck)
|
||||||
|
|
||||||
|
val otherToCheck = othersToCheck.first()
|
||||||
|
othersToCheck.remove(otherToCheck)
|
||||||
|
|
||||||
|
if (thisToCheck.locker !in lockedLockers) {
|
||||||
|
thisToCheck.locker.acquireRead()
|
||||||
|
lockedLockers.add(thisToCheck.locker)
|
||||||
|
}
|
||||||
|
if (otherToCheck.locker !in lockedLockers) {
|
||||||
|
otherToCheck.locker.acquireRead()
|
||||||
|
lockedLockers.add(otherToCheck.locker)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thisToCheck.key != otherToCheck.key || thisToCheck.value != otherToCheck.value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((thisToCheck.leftNode == null).xor(otherToCheck.leftNode == null)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ((thisToCheck.rightNode == null).xor(otherToCheck.rightNode == null)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
thisToCheck.leftNode?.let { leftToCheck.add(it) }
|
||||||
|
thisToCheck.rightNode?.let { leftToCheck.add(it) }
|
||||||
|
|
||||||
|
otherToCheck.leftNode?.let { othersToCheck.add(it) }
|
||||||
|
otherToCheck.rightNode?.let { othersToCheck.add(it) }
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lockedLockers.forEach {
|
||||||
|
runCatching { it.releaseRead() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return leftToCheck.isEmpty() && othersToCheck.isEmpty()
|
||||||
|
}
|
||||||
suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.findNodesInRange(from: K, to: K): Set<SortedMapLikeBinaryTreeNode<K, V>> = findNodesInRange(
|
suspend fun <K, V> SortedMapLikeBinaryTreeNode<K, V>.findNodesInRange(from: K, to: K): Set<SortedMapLikeBinaryTreeNode<K, V>> = findNodesInRange(
|
||||||
from = from,
|
from = from,
|
||||||
to = to,
|
to = to,
|
||||||
|
@@ -0,0 +1,132 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.collections.*
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
|
class SortedMapLikeBinaryTreeNodeTests {
|
||||||
|
@Test
|
||||||
|
fun insertOnZeroLevelWorks() = runTest {
|
||||||
|
val zeroNode = SortedMapLikeBinaryTreeNode(0, 0)
|
||||||
|
zeroNode.upsertSubNode(1, 1)
|
||||||
|
zeroNode.upsertSubNode(-1, -1)
|
||||||
|
|
||||||
|
assertEquals(0, zeroNode.key)
|
||||||
|
assertEquals(1, zeroNode.getRightNode() ?.key)
|
||||||
|
assertEquals(-1, zeroNode.getLeftNode() ?.key)
|
||||||
|
|
||||||
|
assertEquals(0, zeroNode.findNode(0) ?.value)
|
||||||
|
assertEquals(1, zeroNode.findNode(1) ?.value)
|
||||||
|
assertEquals(-1, zeroNode.findNode(-1) ?.value)
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun searchOnZeroLevelWorks() = runTest {
|
||||||
|
val zeroNode = SortedMapLikeBinaryTreeNode(0, 0)
|
||||||
|
val oneNode = zeroNode.upsertSubNode(1, 1)
|
||||||
|
val minusOneNode = zeroNode.upsertSubNode(-1, -1)
|
||||||
|
|
||||||
|
val assertingNodesToSearchQuery = mapOf(
|
||||||
|
setOf(oneNode) to (1 .. 1),
|
||||||
|
setOf(zeroNode, oneNode) to (0 .. 1),
|
||||||
|
setOf(minusOneNode, zeroNode, oneNode) to (-1 .. 1),
|
||||||
|
setOf(minusOneNode, zeroNode) to (-1 .. 0),
|
||||||
|
setOf(minusOneNode) to (-1 .. -1),
|
||||||
|
setOf(zeroNode) to (0 .. 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertingNodesToSearchQuery.forEach {
|
||||||
|
val foundData = zeroNode.findNodesInRange(it.value)
|
||||||
|
assertTrue(foundData.containsAll(it.key))
|
||||||
|
assertTrue(it.key.containsAll(foundData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun deepReInsertOnWorks() = runTest(timeout = 300.seconds) {
|
||||||
|
var zeroNode = SortedMapLikeBinaryTreeNode(0, 0)
|
||||||
|
val rangeRadius = 500
|
||||||
|
val nodes = mutableMapOf<Int, SortedMapLikeBinaryTreeNode<Int, Int>>()
|
||||||
|
for (i in -rangeRadius .. rangeRadius) {
|
||||||
|
nodes[i] = zeroNode.upsertSubNode(i, i)
|
||||||
|
if (i == zeroNode.key) {
|
||||||
|
zeroNode = nodes.getValue(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in -rangeRadius .. rangeRadius) {
|
||||||
|
val expectedNode = nodes.getValue(i)
|
||||||
|
val foundNode = zeroNode.findNode(i)
|
||||||
|
|
||||||
|
assertEquals(expectedNode, foundNode)
|
||||||
|
|
||||||
|
if (expectedNode === zeroNode) continue
|
||||||
|
|
||||||
|
val parentNode = zeroNode.findParentNode(i)
|
||||||
|
assertTrue(
|
||||||
|
parentNode ?.getLeftNode() === expectedNode || parentNode ?.getRightNode() === expectedNode,
|
||||||
|
"It is expected, that parent node with data ${parentNode ?.key} will be parent of ${expectedNode.key}, but its left subnode is ${parentNode ?.getLeftNode() ?.key} and right one is ${parentNode ?.getRightNode() ?.key}"
|
||||||
|
)
|
||||||
|
|
||||||
|
zeroNode.upsertSubNode(i, -i)
|
||||||
|
val foundModifiedNode = zeroNode.findNode(i)
|
||||||
|
assertEquals(foundNode ?.value, foundModifiedNode ?.value ?.times(-1))
|
||||||
|
assertTrue(
|
||||||
|
foundNode != null && foundModifiedNode != null && foundNode.deepEquals(foundModifiedNode)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// @Test
|
||||||
|
// fun deepInsertOnWorks() = runTest(timeout = 240.seconds) {
|
||||||
|
// val zeroNode = SortedMapLikeBinaryTreeNode(0)
|
||||||
|
// val rangeRadius = 500
|
||||||
|
// val nodes = mutableMapOf<Int, SortedMapLikeBinaryTreeNode<Int>>()
|
||||||
|
// for (i in -rangeRadius .. rangeRadius) {
|
||||||
|
// nodes[i] = zeroNode.addSubNode(i)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for (i in -rangeRadius .. rangeRadius) {
|
||||||
|
// val expectedNode = nodes.getValue(i)
|
||||||
|
// val foundNode = zeroNode.findNode(i)
|
||||||
|
//
|
||||||
|
// assertTrue(expectedNode === foundNode)
|
||||||
|
//
|
||||||
|
// if (expectedNode === zeroNode) continue
|
||||||
|
//
|
||||||
|
// val parentNode = zeroNode.findParentNode(i)
|
||||||
|
// assertTrue(
|
||||||
|
// parentNode ?.getLeftNode() === expectedNode || parentNode ?.getRightNode() === expectedNode,
|
||||||
|
// "It is expected, that parent node with data ${parentNode ?.data} will be parent of ${expectedNode.data}, but its left subnode is ${parentNode ?.getLeftNode() ?.data} and right one is ${parentNode ?.getRightNode() ?.data}"
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// val sourceTreeSize = zeroNode.size()
|
||||||
|
//
|
||||||
|
// var previousData = -rangeRadius - 1
|
||||||
|
// for (node in zeroNode) {
|
||||||
|
// assertTrue(nodes[node.data] === node)
|
||||||
|
// assertTrue(previousData == node.data - 1)
|
||||||
|
// previousData = node.data
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// assertTrue(sourceTreeSize == zeroNode.size())
|
||||||
|
// }
|
||||||
|
// @Test
|
||||||
|
// fun deepInsertIteratorWorking() = runTest {
|
||||||
|
// val zeroNode = SortedMapLikeBinaryTreeNode(0)
|
||||||
|
// val rangeRadius = 500
|
||||||
|
// val nodes = mutableMapOf<Int, SortedMapLikeBinaryTreeNode<Int>>()
|
||||||
|
// for (i in -rangeRadius .. rangeRadius) {
|
||||||
|
// nodes[i] = zeroNode.addSubNode(i)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var previousData = -rangeRadius - 1
|
||||||
|
// for (node in zeroNode) {
|
||||||
|
// assertTrue(nodes[node.data] === node)
|
||||||
|
// assertTrue(previousData == node.data - 1)
|
||||||
|
// previousData = node.data
|
||||||
|
// }
|
||||||
|
// assertTrue(previousData == rangeRadius)
|
||||||
|
// }
|
||||||
|
}
|
Reference in New Issue
Block a user