diff --git a/build.gradle.kts b/build.gradle.kts index 26cc008..af0a95e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,7 +35,7 @@ kotlin { kotlin { jvmToolchain { - languageVersion = JavaLanguageVersion.of(25) + languageVersion = JavaLanguageVersion.of(21) vendor = JvmVendorSpec.ADOPTIUM } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8c2419b..0aa6002 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ mockk = "1.14.9" # https://mvnrepository.com/artifact/io.mockk/mockk kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" } -memoize = {group = "org.duckdns.davygora", name = "memoize", version.ref="memoize"} +memoize = { group = "org.duckdns.davygora", name = "memoize", version.ref = "memoize" } # Test diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/AbstractMatrix.kt b/src/main/kotlin/org/duckdns/davygora/matrix/AbstractMatrix.kt new file mode 100644 index 0000000..85d7b88 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/AbstractMatrix.kt @@ -0,0 +1,34 @@ +package org.duckdns.davygora.matrix + +import org.duckdns.davygora.matrix.storage.MatrixStorage + +abstract class AbstractMatrix( + override val xSize: Int, + override val ySize: Int, + protected val matrix: MatrixStorage, +) : Matrix { + override fun toString(): String = + (0.. + "[\t${(0.. this[x, y].toString() }}\t]" + }.joinToString { "\n" } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as AbstractMatrix + + if (xSize != other.xSize) return false + if (ySize != other.ySize) return false + if (matrix != other.matrix) return false + return true + } + + override fun hashCode(): Int { + var result = xSize + result = 31 * result + ySize + result = 31 * result + matrix.hashCode() + return result + } +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/AbstractMutableMatrix.kt b/src/main/kotlin/org/duckdns/davygora/matrix/AbstractMutableMatrix.kt new file mode 100644 index 0000000..8ddea6e --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/AbstractMutableMatrix.kt @@ -0,0 +1,10 @@ +package org.duckdns.davygora.matrix + +import org.duckdns.davygora.matrix.storage.MatrixStorage + +abstract class AbstractMutableMatrix( + xSize: Int, + ySize: Int, + matrix: MatrixStorage, +) : AbstractMatrix(xSize, ySize, matrix), + MutableMatrix diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/Matrix.kt b/src/main/kotlin/org/duckdns/davygora/matrix/Matrix.kt new file mode 100644 index 0000000..4d3fcb9 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/Matrix.kt @@ -0,0 +1,11 @@ +package org.duckdns.davygora.matrix + +interface Matrix { + val xSize: Int + val ySize: Int + + operator fun get( + x: Int, + y: Int, + ): T +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/MutableMatrix.kt b/src/main/kotlin/org/duckdns/davygora/matrix/MutableMatrix.kt new file mode 100644 index 0000000..7261763 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/MutableMatrix.kt @@ -0,0 +1,9 @@ +package org.duckdns.davygora.matrix + +interface MutableMatrix : Matrix { + operator fun set( + x: Int, + y: Int, + value: T, + ) +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixCoordinateOutOfRangeException.kt b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixCoordinateOutOfRangeException.kt new file mode 100644 index 0000000..8b5d0d5 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixCoordinateOutOfRangeException.kt @@ -0,0 +1,7 @@ +package org.duckdns.davygora.matrix.exception + +class MatrixCoordinateOutOfRangeException( + coordName: Char, + coord: Int, + maxCoord: Int, +) : MatrixException("${coordName.uppercaseChar()} coordinate $coord is out of range, allowed is 0..$maxCoord") diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixException.kt b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixException.kt new file mode 100644 index 0000000..8ffddd3 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixException.kt @@ -0,0 +1,6 @@ +package org.duckdns.davygora.matrix.exception + +sealed class MatrixException( + message: String, + cause: Throwable? = null, +) : RuntimeException(message, cause) diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixInvalidSizeException.kt b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixInvalidSizeException.kt new file mode 100644 index 0000000..d8deb5d --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixInvalidSizeException.kt @@ -0,0 +1,6 @@ +package org.duckdns.davygora.matrix.exception + +class MatrixInvalidSizeException( + coordinate: Char, + size: Int, +) : MatrixException("${coordinate.uppercaseChar()} size is invalid: $size (should be > 0)") diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixSizeMismatchException.kt b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixSizeMismatchException.kt new file mode 100644 index 0000000..9847ed1 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixSizeMismatchException.kt @@ -0,0 +1,6 @@ +package org.duckdns.davygora.matrix.exception + +class MatrixSizeMismatchException( + expectedSize: Int, + actualSize: Int, +) : MatrixException("Matrix size mismatch: expected $expectedSize, actual $actualSize") diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/impl/ArrayMatrix.kt b/src/main/kotlin/org/duckdns/davygora/matrix/impl/ArrayMatrix.kt new file mode 100644 index 0000000..5dc8fe2 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/impl/ArrayMatrix.kt @@ -0,0 +1,57 @@ +package org.duckdns.davygora.matrix.impl + +import org.duckdns.davygora.matrix.AbstractMutableMatrix +import org.duckdns.davygora.matrix.Matrix +import org.duckdns.davygora.matrix.exception.MatrixCoordinateOutOfRangeException +import org.duckdns.davygora.matrix.exception.MatrixInvalidSizeException +import org.duckdns.davygora.matrix.exception.MatrixNotRectangularException +import org.duckdns.davygora.matrix.exception.MatrixSizeMismatchException +import org.duckdns.davygora.matrix.storage.MatrixStorage +import org.duckdns.davygora.memoize.memoize + +class ArrayMatrix( + xSize: Int, + ySize: Int, + matrix: MatrixStorage, +) : AbstractMutableMatrix(xSize, ySize, matrix) { + private val size = xSize * ySize + + private val maxX = xSize - 1 + private val maxY = ySize - 1 + + init { + if (ySize < 1) throw MatrixInvalidSizeException('y', ySize) + if (xSize < 1) throw MatrixInvalidSizeException('x', xSize) + if (size != matrix.size) throw MatrixSizeMismatchException(size, matrix.size) + } + + override operator fun get( + x: Int, + y: Int, + ): T = matrix[index(x, y)] + + override operator fun set( + x: Int, + y: Int, + value: T, + ) { + matrix[index(x, y)] = value + } + + private val index = { x: Int, y: Int -> validateY(y) * xSize + validateX(x) }.memoize() + + private val validateX = { x: Int -> validateCoord('x', x, maxX) }.memoize() + private val validateY = { y: Int -> validateCoord('y', y, maxY) }.memoize() + + private fun validateCoord( + coordName: Char, + coord: Int, + maxCoord: Int, + ) = if (coord in + 0..maxCoord + ) { + coord + } else { + throw MatrixCoordinateOutOfRangeException(coordName, coord, maxCoord) + } +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/BooleanStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/BooleanStorage.kt new file mode 100644 index 0000000..6243d0b --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/BooleanStorage.kt @@ -0,0 +1,19 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class BooleanStorage( + val data: BooleanArray, +) : MatrixStorage { + override val size get() = data.size + + override operator fun get(index: Int) = data[index] + + override fun set( + index: Int, + value: Boolean, + ) { + data[index] = value + } + + override fun toString(): String = data.contentToString() +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/ByteStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/ByteStorage.kt new file mode 100644 index 0000000..21dd502 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/ByteStorage.kt @@ -0,0 +1,19 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class ByteStorage( + val data: ByteArray, +) : MatrixStorage { + override val size get() = data.size + + override operator fun get(index: Int) = data[index] + + override fun set( + index: Int, + value: Byte, + ) { + data[index] = value + } + + override fun toString(): String = data.contentToString() +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/CharStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/CharStorage.kt new file mode 100644 index 0000000..52dd8ed --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/CharStorage.kt @@ -0,0 +1,19 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class CharStorage( + val data: CharArray, +) : MatrixStorage { + override val size get() = data.size + + override operator fun get(index: Int) = data[index] + + override fun set( + index: Int, + value: Char, + ) { + data[index] = value + } + + override fun toString(): String = data.contentToString() +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/DoubleStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/DoubleStorage.kt new file mode 100644 index 0000000..7ed8d3f --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/DoubleStorage.kt @@ -0,0 +1,19 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class DoubleStorage( + val data: DoubleArray, +) : MatrixStorage { + override val size get() = data.size + + override operator fun get(index: Int) = data[index] + + override fun set( + index: Int, + value: Double, + ) { + data[index] = value + } + + override fun toString(): String = data.contentToString() +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/FloatStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/FloatStorage.kt new file mode 100644 index 0000000..bde36c9 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/FloatStorage.kt @@ -0,0 +1,19 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class FloatStorage( + val data: FloatArray, +) : MatrixStorage { + override val size get() = data.size + + override operator fun get(index: Int) = data[index] + + override fun set( + index: Int, + value: Float, + ) { + data[index] = value + } + + override fun toString(): String = data.contentToString() +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/IntStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/IntStorage.kt new file mode 100644 index 0000000..ca3cd7b --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/IntStorage.kt @@ -0,0 +1,19 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class IntStorage( + val data: IntArray, +) : MatrixStorage { + override val size get() = data.size + + override operator fun get(index: Int) = data[index] + + override fun set( + index: Int, + value: Int, + ) { + data[index] = value + } + + override fun toString(): String = data.contentToString() +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/LongStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/LongStorage.kt new file mode 100644 index 0000000..e1fe2ce --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/LongStorage.kt @@ -0,0 +1,19 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class LongStorage( + val data: LongArray, +) : MatrixStorage { + override val size get() = data.size + + override operator fun get(index: Int) = data[index] + + override fun set( + index: Int, + value: Long, + ) { + data[index] = value + } + + override fun toString(): String = data.contentToString() +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/MatrixStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/MatrixStorage.kt new file mode 100644 index 0000000..db672aa --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/MatrixStorage.kt @@ -0,0 +1,12 @@ +package org.duckdns.davygora.matrix.storage + +sealed interface MatrixStorage { + val size: Int + + operator fun get(index: Int): T + + operator fun set( + index: Int, + value: T, + ) +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/ObjectStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/ObjectStorage.kt new file mode 100644 index 0000000..964af74 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/ObjectStorage.kt @@ -0,0 +1,19 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class ObjectStorage( + val data: Array, +) : MatrixStorage { + override val size get() = data.size + + override operator fun get(index: Int) = data[index] + + override fun set( + index: Int, + value: T, + ) { + data[index] = value + } + + override fun toString(): String = data.contentToString() +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/storage/ShortStorage.kt b/src/main/kotlin/org/duckdns/davygora/matrix/storage/ShortStorage.kt new file mode 100644 index 0000000..9cbf877 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/ShortStorage.kt @@ -0,0 +1,19 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class ShortStorage( + val data: ShortArray, +) : MatrixStorage { + override val size get() = data.size + + override operator fun get(index: Int) = data[index] + + override fun set( + index: Int, + value: Short, + ) { + data[index] = value + } + + override fun toString(): String = data.contentToString() +}