From d0327d0e902fa9a1c1d75c9bdb32fc46268903e1 Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich Date: Sat, 16 Aug 2025 23:53:40 +0300 Subject: [PATCH] Imported immutable version --- .gitignore | 10 ++ build.gradle.kts | 107 +++++++++++ gradle.properties | 1 + settings.gradle.kts | 2 + .../EnumeratedCollection.kt | 166 ++++++++++++++++++ .../enumerated_collection/_Platform.kt | 7 + .../enumerated_collection/_Platform.kt | 17 ++ .../tests/KotlinStdlibDependencyTest.kt | 28 +++ .../enumerated_collection/_Platform.kt | 10 ++ 9 files changed, 348 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 settings.gradle.kts create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/EnumeratedCollection.kt create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt create mode 100644 src/jvmMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt create mode 100644 src/jvmTest/kotlin/ru/landgrafhomyak/utility/enumerated_collection/tests/KotlinStdlibDependencyTest.kt create mode 100644 src/nonJvmMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..116ea92 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/.idea/ +gradle/ +.gradle/ +build/ +*.class +*.jar +/out/ +/gradlew* +.kotlin/ +/kotlin-js-store \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..2551d64 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,107 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion +import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.* +import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin.xomrk + +buildscript { + repositories { + mavenCentral() + maven("https://maven.landgrafhomyak.ru/") + } + + dependencies { + classpath("ru.landgrafhomyak.kotlin:kotlin-mpp-gradle-build:v0.3k2.1.10") + } +} + +group = "ru.landgrafhomyak.utility" +version = "0.1" + +repositories { + mavenCentral() +} + +xomrk { + kotlin { + setCompatibilityWithKotlin(KotlinVersion.KOTLIN_2_0) + optInContracts() + explicitApi() + noWarnExpectActual() + warningsAsErrors() + + defineAllMultiplatformTargets() + + jvmToolchain(11) + jvm { + withJava() + + compilations.configureEach { + compileJavaTaskProvider?.configure { + targetCompatibility = "1.8" + } + compileTaskProvider.configure { + compilerOptions { + jvmTarget = JvmTarget.JVM_1_8 + freeCompilerArgs.addAll( + "-Xno-call-assertions", + "-Xno-param-assertions", + "-Xno-receiver-assertions" + ) + } + } + } + + tasks.named { t -> t == "${this@jvm.name}Test" }.configureEach { + this as Test + useTestNG() + } + } + + sourceSets { + // if use kotlin("stdlib") gitea ui brokes at paragraph with dependency versions + val kotlinStdlibDependency = "org.jetbrains.kotlin:kotlin-stdlib:${this@kotlin.coreLibrariesVersion}" + + val commonMain by getting { + dependencies { + compileOnly(kotlinStdlibDependency) + } + } + val jvmMain by getting { + dependsOn(commonMain) + dependencies { + compileOnly(kotlinStdlibDependency) + } + } + + val nonJvmMain by creating { + dependsOn(commonMain) + dependencies { + implementation(kotlinStdlibDependency) + } + } + + jvmTest { + dependencies { + implementation("org.testng:testng:7.5.1") + } + } + + configureEach { + when { + // commonMain !in dependsOn -> return@configureEach + !name.endsWith("Main") -> return@configureEach + this@configureEach === commonMain -> return@configureEach + this@configureEach === jvmMain -> return@configureEach + this@configureEach === nonJvmMain -> return@configureEach + } + dependsOn(nonJvmMain) + } + } + } + + publishing { + repositories { + defineXomrkGiteaMavenRepo() + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..7fc6f1f --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +kotlin.code.style=official diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..9597150 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,2 @@ +rootProject.name = "enumerated-collection" + diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/EnumeratedCollection.kt b/src/commonMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/EnumeratedCollection.kt new file mode 100644 index 0000000..f29979f --- /dev/null +++ b/src/commonMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/EnumeratedCollection.kt @@ -0,0 +1,166 @@ +package ru.landgrafhomyak.utility.enumerated_collection + +import kotlin.jvm.JvmStatic + +internal abstract class EnumeratedCollection( + private val _data: Array, +) : List { + protected abstract fun _getElementOrdinal(e: E): Int + abstract override fun toString(): String + + override val size: Int + get() = this._data.size + + override operator fun contains(element: E): Boolean { + _Platform.jvm_assertNotNull(element, "param: element") + + val ordinal = this._getElementOrdinal(element) + if (ordinal >= this.size) + return false + if (ordinal < 0) + throw IllegalArgumentException("Negative ordinal") + return element === this._data[ordinal] + } + + override fun containsAll(elements: Collection): Boolean { + _Platform.jvm_assertNotNull(elements, "param: elements") + + if (elements === this) return true + return elements.all(this::contains) + } + + override fun isEmpty(): Boolean = this._data.isEmpty() + + fun isNotEmpty(): Boolean = this._data.isNotEmpty() + + override operator fun iterator(): Iterator = this._data.iterator() + + override operator fun get(ordinal: Int): E { + if (ordinal >= this.size) + throw IllegalArgumentException("Ordinal out of bounds, are you sure that ordinal owner from this enum?") + if (ordinal < 0) + throw IllegalArgumentException("Negative ordinal") + return this._data[ordinal] + } + + override fun indexOf(element: E): Int { + _Platform.jvm_assertNotNull(element, "param: element") + + @Suppress("LiftReturnOrAssignment") + if (element in this) + return this._getElementOrdinal(element) + else + return -1 + } + + override fun lastIndexOf(element: E): Int = + this.indexOf(element) + + override fun listIterator(): ListIterator = this.ListIteratorImpl(0) + + override fun listIterator(index: Int): ListIterator = this.ListIteratorImpl(index) + + override fun subList(fromIndex: Int, toIndex: Int): List = + this.SublistView(fromIndex, toIndex) + + private object Empty : EnumeratedCollection(emptyArray()) { + override fun toString(): String = "" + + override fun _getElementOrdinal(e: Any): Int = throw IllegalArgumentException("This method unexpected to be invoked") + } + + companion object { + @Suppress("UNCHECKED_CAST") + @JvmStatic + fun empty(): EnumeratedCollection = Empty as EnumeratedCollection + } + + private inner class ListIteratorImpl(private var nextPos: Int) : ListIterator { + override fun next(): E { + if (!this.hasNext()) throw IllegalStateException("Iteration ended") + return this@EnumeratedCollection._data[this.nextPos++] + } + + override fun hasNext(): Boolean = + this.nextPos < this@EnumeratedCollection._data.size + + override fun hasPrevious(): Boolean = this.nextPos > 0 + + override fun previous(): E { + if (!this.hasNext()) throw IllegalStateException("Collection start reached") + return this@EnumeratedCollection._data[--this.nextPos] + } + + override fun nextIndex(): Int = this.nextPos + + override fun previousIndex(): Int = this.nextPos - 1 + } + + private inner class SublistView( + private val _start: Int, + private val _end: Int, + ) : List { + init { + require(this._start <= this._end) { "fromIndex should be greater than toIndex: ${this._start} > ${this._end}" } + } + + override val size: Int = this._end - this._start + + @Suppress("ReplaceSizeCheckWithIsNotEmpty") + override fun isEmpty(): Boolean = this.size != 0 + + override fun contains(element: E): Boolean { + _Platform.jvm_assertNotNull(element, "param: element") + if (element !in this@EnumeratedCollection) return false + return this@EnumeratedCollection._getElementOrdinal(element) in (this._start.. = this.listIterator() + + override fun containsAll(elements: Collection): Boolean { + _Platform.jvm_assertNotNull(elements, "param: elements") + if (elements === this) return true + return elements.all(this::contains) + } + + override fun get(index: Int): E = this@EnumeratedCollection[this._start + index] + + override fun indexOf(element: E): Int { + _Platform.jvm_assertNotNull(element, "param: element") + if (element !in this) return -1 + return this@EnumeratedCollection._getElementOrdinal(element) - this._start + } + + override fun lastIndexOf(element: E): Int = + this.indexOf(element) + + override fun listIterator(): ListIterator = SublistIteratorImpl(this._start) + + override fun listIterator(index: Int): ListIterator = SublistIteratorImpl(this._start + index) + + override fun subList(fromIndex: Int, toIndex: Int): List = + this@EnumeratedCollection.SublistView(this._start + fromIndex, this._start + toIndex) + + + private inner class SublistIteratorImpl(private var nextPos: Int) : ListIterator { + override fun next(): E { + if (!this.hasNext()) throw IllegalStateException("Iteration ended") + return this@EnumeratedCollection._data[this.nextPos++] + } + + override fun hasNext(): Boolean = + this.nextPos < this@SublistView._end + + override fun hasPrevious(): Boolean = this.nextPos > this@SublistView._start + + override fun previous(): E { + if (!this.hasNext()) throw IllegalStateException("Collection start reached") + return this@EnumeratedCollection._data[--this.nextPos] + } + + override fun nextIndex(): Int = this.nextPos - this@SublistView._start + + override fun previousIndex(): Int = this.nextPos - 1 - this@SublistView._start + } + } +} \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt b/src/commonMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt new file mode 100644 index 0000000..fc7a13c --- /dev/null +++ b/src/commonMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt @@ -0,0 +1,7 @@ +package ru.landgrafhomyak.utility.enumerated_collection + +@PublishedApi +internal expect object _Platform { + @PublishedApi + internal inline fun jvm_assertNotNull(x: Any?, name: String) +} \ No newline at end of file diff --git a/src/jvmMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt b/src/jvmMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt new file mode 100644 index 0000000..52e0fca --- /dev/null +++ b/src/jvmMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt @@ -0,0 +1,17 @@ +package ru.landgrafhomyak.utility.enumerated_collection + +import java.util.Objects +import kotlin.contracts.contract + +@PublishedApi +internal actual object _Platform { + @Suppress("NOTHING_TO_INLINE") + @JvmStatic + @PublishedApi + internal actual inline fun jvm_assertNotNull(x: Any?, name: String) { + contract { + returns().implies(x != null) + } + Objects.requireNonNull(x, name) + } +} \ No newline at end of file diff --git a/src/jvmTest/kotlin/ru/landgrafhomyak/utility/enumerated_collection/tests/KotlinStdlibDependencyTest.kt b/src/jvmTest/kotlin/ru/landgrafhomyak/utility/enumerated_collection/tests/KotlinStdlibDependencyTest.kt new file mode 100644 index 0000000..da91b76 --- /dev/null +++ b/src/jvmTest/kotlin/ru/landgrafhomyak/utility/enumerated_collection/tests/KotlinStdlibDependencyTest.kt @@ -0,0 +1,28 @@ +package ru.landgrafhomyak.utility.enumerated_collection.tests + +import org.testng.annotations.Test +import ru.landgrafhomyak.utility.enumerated_collection.EnumeratedCollection + +@Test +class KotlinStdlibDependencyTest { + @Test + fun testNoKotlinStdlib() { + try { + if (KotlinVersion.CURRENT.major != -1) + throw AssertionError("Kotlin stdlib still in runtime classpath") + } catch (_: LinkageError) { + } + } + + private class IntCollection(_data: Array) : EnumeratedCollection(_data) { + override fun _getElementOrdinal(e: Int): Int = e + + override fun toString(): String = "" + + } + + @Test(dependsOnMethods = ["testNoKotlinStdlib"]) + fun testCreationEmpty() { + IntCollection(arrayOf(1, 2, 3, 4)) + } +} \ No newline at end of file diff --git a/src/nonJvmMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt b/src/nonJvmMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt new file mode 100644 index 0000000..74d1485 --- /dev/null +++ b/src/nonJvmMain/kotlin/ru/landgrafhomyak/utility/enumerated_collection/_Platform.kt @@ -0,0 +1,10 @@ +package ru.landgrafhomyak.utility.enumerated_collection + + +@PublishedApi +internal actual object _Platform { + @Suppress("NOTHING_TO_INLINE") + @PublishedApi + internal actual inline fun jvm_assertNotNull(x: Any?, name: String) { + } +} \ No newline at end of file