diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..bb12c88 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Matrix + +TODO 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..52db737 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ # Main -gradle = "9.5.0" # https://gradle.org/releases/ +gradle = "9.5.1" # https://gradle.org/releases/ kotlin = "2.3.21" # https://kotlinlang.org/docs/releases.html#release-details @@ -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/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b52fb7e..df6a6ad 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 diff --git a/gradlew b/gradlew index f640dbc..b9bb139 100755 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob//platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. 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/MatrixNotRectangularException.kt b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixNotRectangularException.kt new file mode 100644 index 0000000..6f44506 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/exception/MatrixNotRectangularException.kt @@ -0,0 +1,5 @@ +package org.duckdns.davygora.matrix.exception + +class MatrixNotRectangularException( + xSizes: Collection, +) : MatrixException("Submitted matrix is not rectangular, different row sizes are $xSizes") 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..87f3b8d --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/impl/ArrayMatrix.kt @@ -0,0 +1,77 @@ +package org.duckdns.davygora.matrix.impl + +import org.duckdns.davygora.matrix.AbstractMutableMatrix +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.matrix.storage.toMatrixStorage +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) + } + + companion object { + inline fun create(values: List>): ArrayMatrix { + val ySize = values.size + val xSize = + when { + ySize > 0 -> { + values.map { row -> row.size }.toSet().let { xSizes -> + if (xSizes.size == 1) xSizes.first() else throw MatrixNotRectangularException(xSizes) + } + } + + else -> { + 0 + } + } + + return ArrayMatrix(xSize, ySize, values.flatten().toMatrixStorage()) + } + } +} diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/impl/MatrixExtentions.kt b/src/main/kotlin/org/duckdns/davygora/matrix/impl/MatrixExtentions.kt new file mode 100644 index 0000000..b36b416 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/impl/MatrixExtentions.kt @@ -0,0 +1,24 @@ +package org.duckdns.davygora.matrix.impl + +import org.duckdns.davygora.matrix.Matrix +import org.duckdns.davygora.matrix.MutableMatrix +import org.duckdns.davygora.matrix.storage.toMatrixStorage +import org.duckdns.davygora.matrix.util.toListChecked + +inline fun mutableMatrixOf( + xSize: Int, + ySize: Int, + vararg matrix: T, +) = ArrayMatrix(xSize, ySize, matrix.asList().toMatrixStorage()) as MutableMatrix + +inline fun matrixOf( + xSize: Int, + ySize: Int, + vararg matrix: T, +) = mutableMatrixOf(xSize, ySize, *matrix) as Matrix + +inline fun Iterable.toMatrix() = ArrayMatrix.create(this.map { it.toListChecked() }) + +inline fun Array.toMatrix() = this.asList().toMatrix() + +inline fun Sequence.toMatrix() = this.toList().toMatrix() 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..24d9779 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/BooleanStorage.kt @@ -0,0 +1,21 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class BooleanStorage( + override 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() +} + +fun BooleanArray.toMatrixStorage() = BooleanStorage(this) 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..d9734f6 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/ByteStorage.kt @@ -0,0 +1,21 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class ByteStorage( + override 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() +} + +fun ByteArray.toMatrixStorage() = ByteStorage(this) 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..ce75597 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/CharStorage.kt @@ -0,0 +1,21 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class CharStorage( + override 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() +} + +fun CharArray.toMatrixStorage() = CharStorage(this) 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..f4e1d72 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/DoubleStorage.kt @@ -0,0 +1,21 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class DoubleStorage( + override 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() +} + +fun DoubleArray.toMatrixStorage() = DoubleStorage(this) 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..c886995 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/FloatStorage.kt @@ -0,0 +1,21 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class FloatStorage( + override 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() +} + +fun FloatArray.toMatrixStorage() = FloatStorage(this) 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..60fcb56 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/IntStorage.kt @@ -0,0 +1,21 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class IntStorage( + override 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() +} + +fun IntArray.toMatrixStorage() = IntStorage(this) 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..033645b --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/LongStorage.kt @@ -0,0 +1,21 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class LongStorage( + override 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() +} + +fun LongArray.toMatrixStorage() = LongStorage(this) 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..207b2e0 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/MatrixStorage.kt @@ -0,0 +1,39 @@ +package org.duckdns.davygora.matrix.storage + +sealed interface MatrixStorage { + val data: Any + + val size: Int + + operator fun get(index: Int): T + + operator fun set( + index: Int, + value: T, + ) +} + +@Suppress("UNCHECKED_CAST") +inline fun List.toMatrixStorage(): MatrixStorage { + firstNotNullOfOrNull { it } + + val elementClass = + firstOrNull() + ?.let { first -> first::class } + ?.takeIf { clazz -> + all { it == null || it::class == clazz } + } + ?: T::class + + return when (elementClass) { + Boolean::class -> (this as List).toBooleanArray().toMatrixStorage() + Byte::class -> (this as List).toByteArray().toMatrixStorage() + Char::class -> (this as List).toCharArray().toMatrixStorage() + Double::class -> (this as List).toDoubleArray().toMatrixStorage() + Float::class -> (this as List).toFloatArray().toMatrixStorage() + Int::class -> (this as List).toIntArray().toMatrixStorage() + Long::class -> (this as List).toLongArray().toMatrixStorage() + Short::class -> (this as List).toShortArray().toMatrixStorage() + else -> this.toTypedArray().toMatrixStorage() + } as MatrixStorage +} 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..80066e3 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/ObjectStorage.kt @@ -0,0 +1,21 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class ObjectStorage( + override 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() +} + +fun Array.toMatrixStorage() = ObjectStorage(this) 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..c9deb80 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/storage/ShortStorage.kt @@ -0,0 +1,21 @@ +package org.duckdns.davygora.matrix.storage + +@JvmInline +value class ShortStorage( + override 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() +} + +fun ShortArray.toMatrixStorage() = ShortStorage(this) diff --git a/src/main/kotlin/org/duckdns/davygora/matrix/util/IterableUtils.kt b/src/main/kotlin/org/duckdns/davygora/matrix/util/IterableUtils.kt new file mode 100644 index 0000000..32ca064 --- /dev/null +++ b/src/main/kotlin/org/duckdns/davygora/matrix/util/IterableUtils.kt @@ -0,0 +1,22 @@ +package org.duckdns.davygora.matrix.util + +@Suppress("UNCHECKED_CAST") +inline fun Any.toListChecked(): List = + when (this) { + is List<*> -> this + is Collection<*> -> toList() + is Iterable<*> -> toList() + is Sequence<*> -> toList() + is Array<*> -> asList() + is BooleanArray -> asList() + is ByteArray -> asList() + is CharArray -> asList() + is DoubleArray -> asList() + is FloatArray -> asList() + is IntArray -> asList() + is LongArray -> asList() + is ShortArray -> asList() + else -> error("Unsupported type: ${this::class}") + }.also { list -> + require(list.all { it is T }) + } as List diff --git a/src/test/kotlin/org/duckdns/davygora/matrix/storage/MatrixStorageTest.kt b/src/test/kotlin/org/duckdns/davygora/matrix/storage/MatrixStorageTest.kt new file mode 100644 index 0000000..f1e9add --- /dev/null +++ b/src/test/kotlin/org/duckdns/davygora/matrix/storage/MatrixStorageTest.kt @@ -0,0 +1,50 @@ +package org.duckdns.davygora.matrix.storage + +import io.kotest.core.spec.style.FunSpec +import io.kotest.datatest.withData +import io.kotest.matchers.shouldBe +import kotlin.reflect.KClass + +class MatrixStorageTest : + FunSpec({ + val testCases: Map, KClass<*>, KClass<*>>> = + mapOf( + "boolean" to Triple(listOf(true, false), BooleanStorage::class, BooleanArray::class), + "byte" to Triple((0..100).map { it.toByte() }, ByteStorage::class, ByteArray::class), + "char" to Triple(('a'..'z') + ('A'..'Z') + ('0'..'9'), CharStorage::class, CharArray::class), + "double" to Triple((0..100).map { it.toDouble() }, DoubleStorage::class, DoubleArray::class), + "float" to Triple((0..100).map { it.toFloat() }, FloatStorage::class, FloatArray::class), + "int" to Triple((0..100).map { it }, IntStorage::class, IntArray::class), + "long" to Triple((0..100).map { it.toLong() }, LongStorage::class, LongArray::class), + "short" to Triple((0..100).map { it.toShort() }, ShortStorage::class, ShortArray::class), + "object" to Triple((0..100).map { first -> Pair(first, (0..100).random()) }, ObjectStorage::class, Array::class), + ) + + context("list of elements of a given type should produce corresponding storage, size, get and set should work") { + withData( + testCases, + ) { (allowedValues, storageClass, dataClass) -> + + // Arrange + + val size = (10..1000).random() + val list = List(size) { allowedValues.random() } + val newList = List(size) { allowedValues.random() } + + // Act + + val storage = list.toMatrixStorage() + + // Assert + + storage::class shouldBe storageClass + storage.data::class shouldBe dataClass + + storage.size shouldBe size + list.forEachIndexed { index, value -> storage[index] shouldBe value } + + newList.forEachIndexed { index, value -> storage[index] = value } + newList.forEachIndexed { index, value -> storage[index] shouldBe value } + } + } + })