From 4f5e261d01e4c27c19966e6b969cf0fc7a5926e5 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 7 Mar 2023 18:59:34 +0600 Subject: [PATCH 1/5] start 0.17.3 --- CHANGELOG.md | 2 ++ gradle.properties | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6af9dbd7769..22adde6cb02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 0.17.3 + ## 0.17.2 * `FSM`: diff --git a/gradle.properties b/gradle.properties index 9e210cbe693..7d16fe68871 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,5 +14,5 @@ crypto_js_version=4.1.1 # Project data group=dev.inmo -version=0.17.2 -android_code_version=184 +version=0.17.3 +android_code_version=185 From 8b9c93bc10a988157e5c86eb4010af75e82f6a4d Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 7 Mar 2023 19:12:12 +0600 Subject: [PATCH 2/5] diffs improvement --- CHANGELOG.md | 4 ++ .../dev/inmo/micro_utils/common/DiffUtils.kt | 63 ++++++++++++++++--- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22adde6cb02..19e95aed9f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 0.17.3 +* `Common`: + * New function `emptyDiff` + * Now you may pass custom `comparisonFun` to all `diff` functions + ## 0.17.2 * `FSM`: diff --git a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt index 367c267ac77..ef27b7f5b5b 100644 --- a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt +++ b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt @@ -36,6 +36,8 @@ data class Diff internal constructor( val added: List<@Serializable(IndexedValueSerializer::class) IndexedValue> ) +fun emptyDiff(): Diff = Diff(emptyList(), emptyList(), emptyList()) + private inline fun performChanges( potentialChanges: MutableList?, IndexedValue?>>, additionsInOld: MutableList, @@ -43,14 +45,14 @@ private inline fun performChanges( changedList: MutableList, IndexedValue>>, removedList: MutableList>, addedList: MutableList>, - strictComparison: Boolean + comparisonFun: (T?, T?) -> Boolean ) { var i = -1 val (oldObject, newObject) = potentialChanges.lastOrNull() ?: return for ((old, new) in potentialChanges.take(potentialChanges.size - 1)) { i++ - val oldOneEqualToNewObject = old ?.value === newObject ?.value || (old ?.value == newObject ?.value && !strictComparison) - val newOneEqualToOldObject = new ?.value === oldObject ?.value || (new ?.value == oldObject ?.value && !strictComparison) + val oldOneEqualToNewObject = comparisonFun(old ?.value, newObject ?.value) + val newOneEqualToOldObject = comparisonFun(new ?.value, oldObject ?.value) if (oldOneEqualToNewObject || newOneEqualToOldObject) { changedList.addAll( potentialChanges.take(i).mapNotNull { @@ -104,7 +106,7 @@ private inline fun performChanges( */ fun Iterable.calculateDiff( other: Iterable, - strictComparison: Boolean = false + comparisonFun: (T?, T?) -> Boolean ): Diff { var i = -1 var j = -1 @@ -132,7 +134,7 @@ fun Iterable.calculateDiff( } when { - oldObject === newObject || (oldObject == newObject && !strictComparison) -> { + comparisonFun(oldObject, newObject) -> { changedObjects.addAll(potentiallyChangedObjects.map { @Suppress("UNCHECKED_CAST") it as Pair, IndexedValue> @@ -143,23 +145,49 @@ fun Iterable.calculateDiff( potentiallyChangedObjects.add(oldObject ?.let { IndexedValue(i, oldObject) } to newObject ?.let { IndexedValue(j, newObject) }) val previousOldsAdditionsSize = additionalInOld.size val previousNewsAdditionsSize = additionalInNew.size - performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, strictComparison) + performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, comparisonFun) i -= (additionalInOld.size - previousOldsAdditionsSize) j -= (additionalInNew.size - previousNewsAdditionsSize) } } } potentiallyChangedObjects.add(null to null) - performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, strictComparison) + performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, comparisonFun) return Diff(removedObjects.toList(), changedObjects.toList(), addedObjects.toList()) } + +/** + * Calculating [Diff] object + * + * @param strictComparison If this parameter set to true, objects which are not equal by links will be used as different + * objects. For example, in case of two "Example" string they will be equal by value, but CAN be different by links + */ +fun Iterable.calculateDiff( + other: Iterable, + strictComparison: Boolean = false +): Diff = calculateDiff( + other, + comparisonFun = if (strictComparison) { + { t1, t2 -> + t1 === t2 + } + } else { + { t1, t2 -> + t1 == t2 + } + } +) inline fun Iterable.diff( other: Iterable, strictComparison: Boolean = false ): Diff = calculateDiff(other, strictComparison) +inline fun Iterable.diff( + other: Iterable, + noinline comparisonFun: (T?, T?) -> Boolean +): Diff = calculateDiff(other, comparisonFun) -inline fun Diff(old: Iterable, new: Iterable) = old.calculateDiff(new) +inline fun Diff(old: Iterable, new: Iterable) = old.calculateDiff(new, strictComparison = false) inline fun StrictDiff(old: Iterable, new: Iterable) = old.calculateDiff(new, true) /** @@ -187,3 +215,22 @@ fun MutableList.applyDiff( set(new.index, new.value) } } + +/** + * This method call [calculateDiff] with strict mode [strictComparison] and then apply differences to [this] + * mutable list + */ +fun MutableList.applyDiff( + source: Iterable, + comparisonFun: (T?, T?) -> Boolean +): Diff = calculateDiff(source, comparisonFun).also { + for (i in it.removed.indices.sortedDescending()) { + removeAt(it.removed[i].index) + } + it.added.forEach { (i, t) -> + add(i, t) + } + it.replaced.forEach { (_, new) -> + set(new.index, new.value) + } +} From d6402c624ed95ae1764b0872bea58623ecc486cb Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 7 Mar 2023 19:14:43 +0600 Subject: [PATCH 3/5] optimization of nonstrict comparison --- .../commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt index ef27b7f5b5b..e93bc3488de 100644 --- a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt +++ b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt @@ -174,7 +174,7 @@ fun Iterable.calculateDiff( } } else { { t1, t2 -> - t1 == t2 + t1 === t2 || t1 == t2 // small optimization for cases when t1 and t2 are the same - comparison will be faster potentially } } ) From 88ee82e1c62ce9df2f900ef8c253febc4fc1c7a0 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 7 Mar 2023 21:50:23 +0600 Subject: [PATCH 4/5] add Diff#isEmpty --- .../kotlin/dev/inmo/micro_utils/common/DiffUtils.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt index e93bc3488de..167c94a21fd 100644 --- a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt +++ b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/DiffUtils.kt @@ -34,7 +34,9 @@ data class Diff internal constructor( */ val replaced: List, @Serializable(IndexedValueSerializer::class) IndexedValue>>, val added: List<@Serializable(IndexedValueSerializer::class) IndexedValue> -) +) { + fun isEmpty(): Boolean = removed.isEmpty() && replaced.isEmpty() && added.isEmpty() +} fun emptyDiff(): Diff = Diff(emptyList(), emptyList(), emptyList()) From 2c7fd320eb6075d32d947c30f4debc91146a07ed Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 7 Mar 2023 22:28:56 +0600 Subject: [PATCH 5/5] fixed --- CHANGELOG.md | 1 + .../kotlin/dev/inmo/micro_utils/common/ToFixed.kt | 6 ++++++ .../kotlin/dev/inmo/micro_utils/common/toFixed.kt | 4 ++++ .../dev/inmo/micro_utils/common/ToFixedActual.kt | 12 ++++++++++++ 4 files changed, 23 insertions(+) create mode 100644 common/src/commonMain/kotlin/dev/inmo/micro_utils/common/ToFixed.kt create mode 100644 common/src/jsMain/kotlin/dev/inmo/micro_utils/common/toFixed.kt create mode 100644 common/src/jvmMain/kotlin/dev/inmo/micro_utils/common/ToFixedActual.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 19e95aed9f7..d23d1cf5cfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 0.17.3 * `Common`: + * Add `fixed` extensions for `Float` and `Double` * New function `emptyDiff` * Now you may pass custom `comparisonFun` to all `diff` functions diff --git a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/ToFixed.kt b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/ToFixed.kt new file mode 100644 index 00000000000..61797b470e2 --- /dev/null +++ b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/ToFixed.kt @@ -0,0 +1,6 @@ +package dev.inmo.micro_utils.common + +val FixedSignsRange = 0 .. 100 + +expect fun Float.fixed(signs: Int): Float +expect fun Double.fixed(signs: Int): Double diff --git a/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/toFixed.kt b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/toFixed.kt new file mode 100644 index 00000000000..44a6d18fd34 --- /dev/null +++ b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/toFixed.kt @@ -0,0 +1,4 @@ +package dev.inmo.micro_utils.common + +actual fun Float.fixed(signs: Int): Float = this.asDynamic().toFixed(signs.coerceIn(FixedSignsRange)).unsafeCast().toFloat() +actual fun Double.fixed(signs: Int): Double = this.asDynamic().toFixed(signs.coerceIn(FixedSignsRange)).unsafeCast().toDouble() diff --git a/common/src/jvmMain/kotlin/dev/inmo/micro_utils/common/ToFixedActual.kt b/common/src/jvmMain/kotlin/dev/inmo/micro_utils/common/ToFixedActual.kt new file mode 100644 index 00000000000..9ef32711fce --- /dev/null +++ b/common/src/jvmMain/kotlin/dev/inmo/micro_utils/common/ToFixedActual.kt @@ -0,0 +1,12 @@ +package dev.inmo.micro_utils.common + +import java.math.BigDecimal +import java.math.RoundingMode + +actual fun Float.fixed(signs: Int): Float = BigDecimal.valueOf(this.toDouble()) + .setScale(signs.coerceIn(FixedSignsRange), RoundingMode.HALF_UP) + .toFloat(); + +actual fun Double.fixed(signs: Int): Double = BigDecimal.valueOf(this) + .setScale(signs.coerceIn(FixedSignsRange), RoundingMode.HALF_UP) + .toDouble();