Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@

### Metrics
```text
15288 number of properties
10573 number of functions
8954 number of classes
240 number of packages
3543 number of kt files
15600 number of properties
10708 number of functions
9006 number of classes
241 number of packages
3579 number of kt files
```


### Complexity Report
```text
267458 lines of code (loc)
166374 source lines of code (sloc)
121548 logical lines of code (lloc)
72562 comment lines of code (cloc)
25100 cyclomatic complexity (mcc)
20431 cognitive complexity
270027 lines of code (loc)
168414 source lines of code (sloc)
122999 logical lines of code (lloc)
72635 comment lines of code (cloc)
25394 cyclomatic complexity (mcc)
20712 cognitive complexity
0 number of total code smells
43 comment source ratio
206 mcc per 1,000 lloc
```
```
164 changes: 164 additions & 0 deletions api/Kotlin-Lab.api
Original file line number Diff line number Diff line change
Expand Up @@ -20091,6 +20091,170 @@ public final class dev/shtanko/concurrency/coroutines/sort/CoroutinesMergeSort {
public static synthetic fun perform$default (Ldev/shtanko/concurrency/coroutines/sort/CoroutinesMergeSort;[IIILjava/lang/Object;)[I
}

public abstract class dev/shtanko/concurrency/coroutines/tasks/BaseTask : dev/shtanko/concurrency/coroutines/tasks/Task {
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lkotlinx/coroutines/CoroutineDispatcher;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lkotlinx/coroutines/CoroutineDispatcher;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun cancel ()V
protected abstract fun execute (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getDescription ()Ljava/lang/String;
public fun getName ()Ljava/lang/String;
public fun getProgress ()Lkotlinx/coroutines/flow/StateFlow;
public fun getStatus ()Lkotlinx/coroutines/flow/StateFlow;
public fun run (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
protected final fun updateProgress (F)V
protected final fun updateStatus (Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/BinaryTreeTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (I)V
public synthetic fun <init> (IILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/BinaryTreeTask$TreeNode {
public fun <init> (I)V
public final fun getLeft ()Ldev/shtanko/concurrency/coroutines/tasks/BinaryTreeTask$TreeNode;
public final fun getRight ()Ldev/shtanko/concurrency/coroutines/tasks/BinaryTreeTask$TreeNode;
public final fun getValue ()I
public final fun setLeft (Ldev/shtanko/concurrency/coroutines/tasks/BinaryTreeTask$TreeNode;)V
public final fun setRight (Ldev/shtanko/concurrency/coroutines/tasks/BinaryTreeTask$TreeNode;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/CompressionTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (I)V
public synthetic fun <init> (IILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/CryptographicTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (I)V
public synthetic fun <init> (IILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/GraphAlgorithmsTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (I)V
public synthetic fun <init> (IILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/HashComputationTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (I)V
public synthetic fun <init> (IILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/ImageProcessingTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (II)V
public synthetic fun <init> (IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/MainKt {
public static final fun main ()V
public static synthetic fun main ([Ljava/lang/String;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/MandelbrotTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (III)V
public synthetic fun <init> (IIIILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/MatrixMultiplicationTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (I)V
public synthetic fun <init> (IILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/MergeSortTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (ILkotlinx/coroutines/CoroutineDispatcher;)V
public synthetic fun <init> (ILkotlinx/coroutines/CoroutineDispatcher;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/NeuralNetworkTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (IIII)V
public synthetic fun <init> (IIIIILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/PrimeCalculationTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (ILkotlinx/coroutines/CoroutineDispatcher;)V
public synthetic fun <init> (ILkotlinx/coroutines/CoroutineDispatcher;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/QuickSortTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (ILkotlinx/coroutines/CoroutineDispatcher;)V
public synthetic fun <init> (ILkotlinx/coroutines/CoroutineDispatcher;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/SortingTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (I)V
public synthetic fun <init> (IILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/shtanko/concurrency/coroutines/tasks/StringMatchingTask : dev/shtanko/concurrency/coroutines/tasks/BaseTask {
public fun <init> ()V
public fun <init> (II)V
public synthetic fun <init> (IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public abstract interface class dev/shtanko/concurrency/coroutines/tasks/Task {
public abstract fun cancel ()V
public abstract fun getDescription ()Ljava/lang/String;
public abstract fun getName ()Ljava/lang/String;
public abstract fun getProgress ()Lkotlinx/coroutines/flow/StateFlow;
public abstract fun getStatus ()Lkotlinx/coroutines/flow/StateFlow;
public abstract fun run (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class dev/shtanko/concurrency/coroutines/tasks/TaskResult {
public fun <init> (Ljava/lang/String;Ljava/lang/Object;JLdev/shtanko/concurrency/coroutines/tasks/TaskStatus;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/Object;
public final fun component3 ()J
public final fun component4 ()Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;
public final fun copy (Ljava/lang/String;Ljava/lang/Object;JLdev/shtanko/concurrency/coroutines/tasks/TaskStatus;)Ldev/shtanko/concurrency/coroutines/tasks/TaskResult;
public static synthetic fun copy$default (Ldev/shtanko/concurrency/coroutines/tasks/TaskResult;Ljava/lang/String;Ljava/lang/Object;JLdev/shtanko/concurrency/coroutines/tasks/TaskStatus;ILjava/lang/Object;)Ldev/shtanko/concurrency/coroutines/tasks/TaskResult;
public fun equals (Ljava/lang/Object;)Z
public final fun getExecutionTime ()J
public final fun getResult ()Ljava/lang/Object;
public final fun getStatus ()Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;
public final fun getTaskName ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class dev/shtanko/concurrency/coroutines/tasks/TaskStatus : java/lang/Enum {
public static final field CANCELLED Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;
public static final field COMPLETED Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;
public static final field ERROR Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;
public static final field IDLE Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;
public static final field RUNNING Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;
public static fun getEntries ()Lkotlin/enums/EnumEntries;
public static fun valueOf (Ljava/lang/String;)Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;
public static fun values ()[Ldev/shtanko/concurrency/coroutines/tasks/TaskStatus;
}

public final class dev/shtanko/concurrency/coroutines/tasks/TaskViewModel {
public fun <init> ()V
public fun <init> (Lkotlinx/coroutines/CoroutineDispatcher;)V
public synthetic fun <init> (Lkotlinx/coroutines/CoroutineDispatcher;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun addTask (Ldev/shtanko/concurrency/coroutines/tasks/Task;)V
public final fun cancelAllTasks ()V
public final fun clearResults ()V
public final fun clearTasks ()V
public final fun getResults ()Lkotlinx/coroutines/flow/StateFlow;
public final fun getTasks ()Lkotlinx/coroutines/flow/StateFlow;
public final fun onCleared ()V
public final fun runAllTasks ()V
public final fun runTask (Ldev/shtanko/concurrency/coroutines/tasks/Task;)V
}

public final class dev/shtanko/concurrency/jvm/deadlock/DeadLockSample {
public static final field INSTANCE Ldev/shtanko/concurrency/jvm/deadlock/DeadLockSample;
public static final fun main ([Ljava/lang/String;)V
Expand Down
2 changes: 1 addition & 1 deletion config/main.md.bak
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<a href="https://hitsofcode.com/github/ashtanko/kotlab/view?branch=main"><img alt="Hits-of-Code" src="https://hitsofcode.com/github/ashtanko/kotlab?branch=main"/></a>
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2Fashtanko%2Falgorithms-in-depth?ref=badge_shield&issueType=license"><img alt="FOSSA Status" src="https://app.fossa.com/api/projects/git%2Bgithub.com%2Fashtanko%2Falgorithms-in-depth.svg?type=shield&issueType=license"/></a>
<a href="https://ktlint.github.io/"><img alt="CodeStyle" src="https://img.shields.io/badge/code%20style-%E2%9D%A4-FF4081.svg"/></a>
<a href="https://kotlinlang.org/"><img alt="Kotlin Version" src="https://img.shields.io/badge/kotlin-2.2.0-blue.svg"/></a>
<a href="https://kotlinlang.org/"><img alt="Kotlin Version" src="https://img.shields.io/badge/kotlin-2.2.10-blue.svg"/></a>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Avoid committing backup files; also verify Kotlin badge matches build toolchain

.bak files are typically transient and shouldn’t be versioned. Consider removing this file or moving it under docs with a proper name. While you’re here, confirm the 2.2.10 badge aligns with the Kotlin toolchain used by Gradle and libs.versions.toml.

Run this script to surface Kotlin versions used in the repo and the badge versions referenced in docs:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Kotlin versions in build files (plugins/deps):"
rg -n -C1 -g '!**/build/**' -P '(org\.jetbrains\.kotlin|kotlin-stdlib|kotlinx\-coroutines|kotlin\("jvm"\)|kotlin\("android"\)|kotlin\("multiplatform"\))\W*[:= ]*\W*["'\'']?([0-9]+\.[0-9]+\.[0-9]+)?' || true

echo
echo "Kotlin version badges in docs (README, config/*):"
rg -n -C0 -P 'img\.shields\.io/badge/kotlin-([0-9]+\.[0-9]+\.[0-9]+)' README.md config/ || true

Length of output: 12494


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locating [versions] section in gradle/libs.versions.toml:"
rg -n '^\[versions\]' -n gradle/libs.versions.toml -A5 || true

echo
echo "Extracting 'kotlin' version definition:"
rg -nP '^\s*kotlin\s*=\s*".*"' -n gradle/libs.versions.toml || true

Length of output: 705


Remove the backup file config/main.md.bak

  • Delete config/main.md.bak – backup files shouldn’t be committed.
  • No action needed on the Kotlin badge: it’s 2.2.10, which matches the kotlin = "2.2.10" entry in gradle/libs.versions.toml.
🤖 Prompt for AI Agents
In config/main.md.bak around line 13, this is a backup file that should not be
committed; remove config/main.md.bak from the repository and the commit (delete
the file), and if already added to git, run git rm --cached or git rm to remove
it and update .gitignore to prevent future .bak files from being committed.

<a href="https://sonarcloud.io/summary/new_code?id=ashtanko_kotlab"><img alt="Quality Gate Status" src="https://sonarcloud.io/api/project_badges/measure?project=ashtanko_kotlab&metric=alert_status"/></a>
<a href="https://sonarcloud.io/summary/new_code?id=ashtanko_kotlab"><img alt="Bugs" src="https://sonarcloud.io/api/project_badges/measure?project=ashtanko_kotlab&metric=bugs"/></a>
<a href="https://sonarcloud.io/summary/new_code?id=ashtanko_kotlab"><img alt="Code Smells" src="https://sonarcloud.io/api/project_badges/measure?project=ashtanko_kotlab&metric=code_smells"/></a>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package dev.shtanko.concurrency.coroutines.tasks

import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.withContext

@Suppress("TooGenericExceptionCaught")
abstract class BaseTask<R>(
override val name: String,
override val description: String,
private val dispatcher: CoroutineDispatcher = Dispatchers.Default,
) : Task<R> {
private val _progress = MutableStateFlow(0f)
override val progress: StateFlow<Float> = _progress.asStateFlow()

private val _status = MutableStateFlow(TaskStatus.IDLE)
override val status: StateFlow<TaskStatus> = _status.asStateFlow()

private var job: Job? = null

protected fun updateProgress(value: Float) {
_progress.value = value.coerceIn(0f, 1f)
}

protected fun updateStatus(status: TaskStatus) {
_status.value = status
}

override fun cancel() {
job?.cancel()
updateStatus(TaskStatus.CANCELLED)
}

override suspend fun run(): R {
return withContext(dispatcher) {
job = coroutineContext[Job]
updateStatus(TaskStatus.RUNNING)
updateProgress(0f)

try {
val result = execute()
updateStatus(TaskStatus.COMPLETED)
updateProgress(1f)
result
} catch (e: CancellationException) {
updateStatus(TaskStatus.CANCELLED)
throw e
} catch (e: Exception) {
updateStatus(TaskStatus.ERROR)
throw e
}
}
}

protected abstract suspend fun execute(): R
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@file:Suppress("MagicNumber")

package dev.shtanko.concurrency.coroutines.tasks

import kotlin.random.Random
import kotlinx.coroutines.yield

class BinaryTreeTask(
private val nodeCount: Int = 50_000,
) : BaseTask<String>(
name = "Binary Tree Operations",
description = "Building and traversing $nodeCount nodes",
) {
class TreeNode(val value: Int) {
var left: TreeNode? = null
var right: TreeNode? = null
}

override suspend fun execute(): String {
var root: TreeNode? = null
val values = List(nodeCount) { Random.nextInt(1000000) }

// Build tree
for ((index, value) in values.withIndex()) {
if (index % 500 == 0) {
yield()
updateProgress(index.toFloat() / (nodeCount * 2))
}
root = insert(root, value)
}

// Calculate tree properties
val height = calculateHeight(root)
val nodeSum = sumNodes(root)

return "Height: $height, Sum: $nodeSum"
}

private fun insert(root: TreeNode?, value: Int): TreeNode {
if (root == null) return TreeNode(value)

if (value < root.value) {
root.left = insert(root.left, value)
} else {
root.right = insert(root.right, value)
}
return root
}

private suspend fun calculateHeight(node: TreeNode?): Int {
if (node == null) return 0
return 1 + maxOf(calculateHeight(node.left), calculateHeight(node.right))
}

private suspend fun sumNodes(node: TreeNode?): Long {
if (node == null) return 0
return node.value + sumNodes(node.left) + sumNodes(node.right)
}
Comment on lines +55 to +58
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Compilation error: returning Int where Long is required

sumNodes is declared to return Long but returns 0 (Int) for the null case. Use 0L to match the return type.

Apply this diff:

-    private suspend fun sumNodes(node: TreeNode?): Long {
-        if (node == null) return 0
-        return node.value + sumNodes(node.left) + sumNodes(node.right)
-    }
+    private suspend fun sumNodes(node: TreeNode?): Long {
+        if (node == null) return 0L
+        return node.value + sumNodes(node.left) + sumNodes(node.right)
+    }
🤖 Prompt for AI Agents
In src/main/kotlin/dev/shtanko/concurrency/coroutines/tasks/BinaryTreeTask.kt
around lines 55 to 58, the function sumNodes is declared to return Long but
returns the Int literal 0 for the null case; change the null branch to return 0L
so the literal is Long and all arithmetic uses Long (i.e., replace "return 0"
with "return 0L").

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@file:Suppress("MagicNumber")

package dev.shtanko.concurrency.coroutines.tasks

import kotlin.random.Random
import kotlinx.coroutines.yield

class CompressionTask(
private val dataSize: Int = 100_000,
) : BaseTask<Double>(
name = "Data Compression",
description = "LZ77 compression of $dataSize bytes",
) {
override suspend fun execute(): Double {
val data = ByteArray(dataSize) { (Random.nextInt(26) + 'a'.code).toByte() }
val compressed = mutableListOf<Triple<Int, Int, Byte>>() // (offset, length, next char)

var i = 0
while (i < data.size) {
if (i % 1000 == 0) {
yield()
updateProgress(i.toFloat() / dataSize)
}

var maxLength = 0
var maxOffset = 0
val searchStart = maxOf(0, i - 4096) // Search window

for (j in searchStart until i) {
var length = 0
while (i + length < data.size &&
length < 255 &&
data[j + length] == data[i + length]
) {
length++
}

if (length > maxLength) {
maxLength = length
maxOffset = i - j
}
}

val nextChar = if (i + maxLength < data.size) data[i + maxLength] else 0
compressed.add(Triple(maxOffset, maxLength, nextChar))
i += maxLength + 1
Comment on lines +44 to +46
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix type mismatch for nextChar (compile-time error).

The else branch uses an Int literal (0) where a Byte is required, leading to a type mismatch when constructing Triple<Int, Int, Byte>.

Apply this diff:

-            val nextChar = if (i + maxLength < data.size) data[i + maxLength] else 0
+            val nextChar = if (i + maxLength < data.size) data[i + maxLength] else 0.toByte()
🤖 Prompt for AI Agents
In src/main/kotlin/dev/shtanko/concurrency/coroutines/tasks/CompressionTask.kt
around lines 44 to 46, the else branch assigns an Int literal (0) to nextChar
while data elements are Byte, causing a type mismatch when building Triple<Int,
Int, Byte>; change the literal to a Byte (e.g., 0.toByte()) so nextChar is a
Byte and the Triple type matches.

}

val compressionRatio = compressed.size * 3.0 / dataSize
return compressionRatio
}
}
Loading
Loading