From 96969b723569a270e895debf092cd869c93ff02b Mon Sep 17 00:00:00 2001 From: Teodor Grigor Date: Wed, 4 Sep 2024 13:44:14 +0300 Subject: [PATCH 1/2] Migrate Project to CrossLens Library --- gradle/libs.versions.toml | 2 + sudoklify-core/api/sudoklify-core.api | 15 --- sudoklify-core/build.gradle.kts | 3 + .../teogor/sudoklify/schema/SudokuSchema.kt | 2 +- .../teogor/sudoklify/util/HashCodeBuilder.kt | 118 ------------------ .../sudoklify/util/HashCodeBuilderTest.kt | 105 ---------------- 6 files changed, 6 insertions(+), 239 deletions(-) delete mode 100644 sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/util/HashCodeBuilder.kt delete mode 100644 sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/util/HashCodeBuilderTest.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ce5a467..21a8116 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ compose-plugin = "1.7.0-alpha03" androidx-activity-compose = "1.9.1" androidx-lifecycle = "2.8.0" teogor-paletteon = "1.0.0-alpha01" +teogor-crosslens = "1.0.0-alpha02" [libraries] androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" } @@ -27,6 +28,7 @@ jetbrains-kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.r jetbrains-kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } jetbrains-kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "jetbrains-kotlinx-datetime" } teogor-paletteon-core = { module = "dev.teogor.paletteon:paletteon-core", version.ref = "teogor-paletteon" } +teogor-crosslens-core = { module = "dev.teogor.crosslens:crosslens-core", version.ref = "teogor-crosslens" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } diff --git a/sudoklify-core/api/sudoklify-core.api b/sudoklify-core/api/sudoklify-core.api index 2713c65..b679539 100644 --- a/sudoklify-core/api/sudoklify-core.api +++ b/sudoklify-core/api/sudoklify-core.api @@ -282,18 +282,3 @@ public final class dev/teogor/sudoklify/util/BoardConversionsKt { public static final fun toBoard (Ljava/lang/String;Ldev/teogor/sudoklify/components/Dimension;)[[Ljava/lang/String; } -public final class dev/teogor/sudoklify/util/HashCodeBuilder { - public fun ()V - public fun (II)V - public synthetic fun (IIILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun append (Ljava/lang/Object;)Ldev/teogor/sudoklify/util/HashCodeBuilder; - public final fun build ()I -} - -public final class dev/teogor/sudoklify/util/HashCodeBuilderKt { - public static final fun buildHashCode (IILkotlin/jvm/functions/Function1;)I - public static synthetic fun buildHashCode$default (IILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I - public static final fun buildLazyHashCode (Lkotlin/jvm/functions/Function1;)Lkotlin/Lazy; - public static final fun lazyHashCode (Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy; -} - diff --git a/sudoklify-core/build.gradle.kts b/sudoklify-core/build.gradle.kts index 64fa8a9..0556177 100644 --- a/sudoklify-core/build.gradle.kts +++ b/sudoklify-core/build.gradle.kts @@ -68,6 +68,9 @@ kotlin { val commonMain by getting { dependencies { implementation(libs.jetbrains.kotlinx.datetime) + + implementation(libs.teogor.crosslens.core) + api(projects.sudoklifyCommon) api(projects.sudoklifyTokenizer) } diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchema.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchema.kt index cbe2112..9872509 100644 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchema.kt +++ b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/schema/SudokuSchema.kt @@ -18,12 +18,12 @@ package dev.teogor.sudoklify.schema +import dev.teogor.crosslens.core.buildLazyHashCode import dev.teogor.sudoklify.ExperimentalSudoklifyApi import dev.teogor.sudoklify.components.Difficulty import dev.teogor.sudoklify.components.Dimension import dev.teogor.sudoklify.tokenizer.SudokuString import dev.teogor.sudoklify.tokenizer.toSudokuString -import dev.teogor.sudoklify.util.buildLazyHashCode /** * Represents a schema for generating Sudoku puzzles. diff --git a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/util/HashCodeBuilder.kt b/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/util/HashCodeBuilder.kt deleted file mode 100644 index 005d135..0000000 --- a/sudoklify-core/src/commonMain/kotlin/dev/teogor/sudoklify/util/HashCodeBuilder.kt +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2024 Teogor (Teodor Grigor) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.teogor.sudoklify.util - -import dev.teogor.sudoklify.InternalSudoklifyApi -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -/** - * A utility class for building hash codes using a custom algorithm. - * - * @property initialValue The initial value for the hash code computation. Defaults to `31`. - * @property multiplier The multiplier used to calculate the hash code. Defaults to `31`. - * - * This class allows you to append values to a hash code and compute the final hash code using - * a specified multiplier and initial value. - * - * @see [buildHashCode] for creating a hash code using a builder action. - */ -class HashCodeBuilder( - private val initialValue: Int = 31, - private val multiplier: Int = 31, -) { - private var hashCode = initialValue - - /** - * Appends the hash code of the given value to the current hash code. - * - * @param value The value to append. If the value is an array, its deep hash code is used. - * Null values are treated as `0`. If the hash code of the value is `0`, it is - * not included. - * @return The current instance of [HashCodeBuilder], for chaining. - * - * @see [buildHashCode] for an example of how to use this method. - */ - fun append(value: Any?): HashCodeBuilder = - apply { - val currentHashCode = - when (value) { - is Array<*> -> value.contentDeepHashCode() - else -> value?.hashCode() ?: 0 - } - if (currentHashCode != 0) { - hashCode = multiplier * hashCode + currentHashCode - } - } - - /** - * Computes and returns the final hash code. - * - * @return The final hash code computed by the builder. - * - * @see [buildHashCode] for an example of how to use this method. - */ - fun build(): Int = hashCode -} - -/** - * Creates a hash code using a custom builder action. - * - * @param initialValue The initial value for the hash code computation. Defaults to `31`. - * @param multiplier The multiplier used in hash code calculation. Defaults to `31`. - * @param builderAction A lambda function to build the hash code using [HashCodeBuilder]. - * - * @return The computed hash code. - * - * @see [HashCodeBuilder] for details on how hash codes are computed. - */ -@OptIn(ExperimentalContracts::class) -inline fun buildHashCode( - initialValue: Int = 31, - multiplier: Int = 31, - builderAction: HashCodeBuilder.() -> Unit, -): Int { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return HashCodeBuilder(initialValue, multiplier).apply(builderAction).build() -} - -/** - * Creates a lazy hash code using an initializer function. - * - * @param initializer A function that returns the hash code value. - * - * @return A [Lazy] instance that computes the hash code when accessed. - * - * @see [buildLazyHashCode] for creating a lazy hash code using a [HashCodeBuilder]. - */ -@InternalSudoklifyApi -fun lazyHashCode(initializer: () -> Int): Lazy = - lazy(LazyThreadSafetyMode.PUBLICATION) { initializer() } - -/** - * Creates a lazy hash code using a builder initializer function. - * - * @param initializer A lambda function to build the hash code using [HashCodeBuilder]. - * - * @return A [Lazy] instance that computes the hash code when accessed. - * - * @see [HashCodeBuilder] for details on hash code computation. - */ -@OptIn(InternalSudoklifyApi::class) -inline fun buildLazyHashCode(crossinline initializer: HashCodeBuilder.() -> Unit): Lazy = - lazyHashCode { HashCodeBuilder().apply(initializer).build() } diff --git a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/util/HashCodeBuilderTest.kt b/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/util/HashCodeBuilderTest.kt deleted file mode 100644 index 254d983..0000000 --- a/sudoklify-core/src/commonTest/kotlin/dev/teogor/sudoklify/util/HashCodeBuilderTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2024 Teogor (Teodor Grigor) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.teogor.sudoklify.util - -import kotlin.test.Test -import kotlin.test.assertEquals - -class HashCodeBuilderTest { - @Test - fun initialHashCode_shouldBe31() { - val builder = - HashCodeBuilder() - .build() - assertEquals(31, builder) - } - - @Test - fun appendNullValue_shouldResultInInitialHashCode() { - val hashCodeActual = - buildHashCode { - append(null) - } - val hashCodeExpected = 31 - assertEquals( - expected = hashCodeExpected, - actual = hashCodeActual, - message = "Null value should result in initial hash code (31)", - ) - } - - @Test - fun appendSingleValue_shouldCalculateHashCodeCorrectly() { - val hashCodeActual = - buildHashCode { - append("test") - } - val hashCodeExpected = 31 * 31 + "test".hashCode() - assertEquals( - expected = hashCodeExpected, - actual = hashCodeActual, - message = "Hash code should be calculated using initial value and string's hash code", - ) - } - - @Test - fun appendMultipleValues_shouldCalculateHashCodeCorrectly() { - val hashCodeActual = - buildHashCode { - append("test") - append(123) - append(45.67) - } - val hashCodeExpected = - ( - (31 * 31 + "test".hashCode()) * 31 + 123.hashCode() - ) * 31 + 45.67.hashCode() - assertEquals( - expected = hashCodeExpected, - actual = hashCodeActual, - ) - } - - @Test - fun appendSameValueMultipleTimes_shouldCalculateHashCodeCorrectly() { - val hashCodeActual = - buildHashCode { - append("same") - append("same") - append("same") - } - val hashCodeExpected = - ( - (31 * 31 + "same".hashCode()) * 31 + "same".hashCode() - ) * 31 + "same".hashCode() - assertEquals( - expected = hashCodeExpected, - actual = hashCodeActual, - ) - } - - @Test - fun hashCodeConsistency_shouldBeMaintained() { - val builder = - HashCodeBuilder() - .append("consistent") - .append("value") - val hashCode1 = builder.build() - val hashCode2 = builder.build() - assertEquals(hashCode1, hashCode2) - } -} From afe820acb210c980482f519f7f9b16405bac417c Mon Sep 17 00:00:00 2001 From: Teodor Grigor Date: Wed, 4 Sep 2024 14:00:25 +0300 Subject: [PATCH 2/2] Resolve Dokka application issue in subprojects configuration --- build.gradle.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 57d0c1a..c8670c5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -171,7 +171,7 @@ subprojects { val excludedProjects = listOf( projects.sudoklify, - projects.sudoklify.demo.composeApp, + projects.sudoklify.demo, ) apiValidation { @@ -183,7 +183,6 @@ apiValidation { subprojects { val paths = excludedProjects.map { it.identityPath.path } - println("This is the path: $path for subproject: $path") if (!paths.contains(this.path)) { apply() }