From 59a6d4aac814ea829a4af7ed74679f4d5cde92cd Mon Sep 17 00:00:00 2001 From: Matthew Nelson Date: Thu, 2 Jan 2025 08:54:00 -0500 Subject: [PATCH 1/2] Make Counters final with public functions --- library/core/api/core.api | 23 +++---- library/core/api/core.klib.api | 19 +++--- .../kotlin/org/kotlincrypto/core/Counter.kt | 64 ++++++++++--------- .../org/kotlincrypto/core/CounterUnitTest.kt | 53 ++++++++------- .../org/kotlincrypto/core/TestBit32Counter.kt | 34 ---------- 5 files changed, 86 insertions(+), 107 deletions(-) delete mode 100644 library/core/src/commonTest/kotlin/org/kotlincrypto/core/TestBit32Counter.kt diff --git a/library/core/api/core.api b/library/core/api/core.api index eab9c5c..27af951 100644 --- a/library/core/api/core.api +++ b/library/core/api/core.api @@ -6,41 +6,42 @@ public abstract interface class org/kotlincrypto/core/Copyable { public abstract fun copy ()Ljava/lang/Object; } -public abstract class org/kotlincrypto/core/Counter { +public abstract class org/kotlincrypto/core/Counter : org/kotlincrypto/core/Copyable, org/kotlincrypto/core/Resettable { public final fun equals (Ljava/lang/Object;)Z public final fun hashCode ()I - protected abstract fun increment ()V - protected abstract fun reset ()V + public abstract fun increment ()V public final fun toString ()Ljava/lang/String; } -public abstract class org/kotlincrypto/core/Counter$Bit32 : org/kotlincrypto/core/Counter { +public final class org/kotlincrypto/core/Counter$Bit32 : org/kotlincrypto/core/Counter { public static final field Companion Lorg/kotlincrypto/core/Counter$Bit32$Companion; public static final field MAX_INCREMENT I public final field incrementBy I public fun (I)V public fun (III)V - public fun (Lorg/kotlincrypto/core/Counter$Bit32;)V + public synthetic fun copy ()Ljava/lang/Object; + public fun copy ()Lorg/kotlincrypto/core/Counter$Bit32; public final fun hi ()I - protected fun increment ()V + public fun increment ()V public final fun lo ()I - protected fun reset ()V + public fun reset ()V } public final class org/kotlincrypto/core/Counter$Bit32$Companion { } -public abstract class org/kotlincrypto/core/Counter$Bit64 : org/kotlincrypto/core/Counter { +public final class org/kotlincrypto/core/Counter$Bit64 : org/kotlincrypto/core/Counter { public static final field Companion Lorg/kotlincrypto/core/Counter$Bit64$Companion; public static final field MAX_INCREMENT J public final field incrementBy J public fun (J)V public fun (JJJ)V - public fun (Lorg/kotlincrypto/core/Counter$Bit64;)V + public synthetic fun copy ()Ljava/lang/Object; + public fun copy ()Lorg/kotlincrypto/core/Counter$Bit64; public final fun hi ()J - protected fun increment ()V + public fun increment ()V public final fun lo ()J - protected fun reset ()V + public fun reset ()V } public final class org/kotlincrypto/core/Counter$Bit64$Companion { diff --git a/library/core/api/core.klib.api b/library/core/api/core.klib.api index d8d9135..515e061 100644 --- a/library/core/api/core.klib.api +++ b/library/core/api/core.klib.api @@ -32,17 +32,15 @@ abstract interface org.kotlincrypto.core/Updatable { // org.kotlincrypto.core/Up abstract fun update(kotlin/ByteArray, kotlin/Int, kotlin/Int) // org.kotlincrypto.core/Updatable.update|update(kotlin.ByteArray;kotlin.Int;kotlin.Int){}[0] } -sealed class org.kotlincrypto.core/Counter { // org.kotlincrypto.core/Counter|null[0] +sealed class org.kotlincrypto.core/Counter : org.kotlincrypto.core/Copyable, org.kotlincrypto.core/Resettable { // org.kotlincrypto.core/Counter|null[0] abstract fun increment() // org.kotlincrypto.core/Counter.increment|increment(){}[0] - abstract fun reset() // org.kotlincrypto.core/Counter.reset|reset(){}[0] final fun equals(kotlin/Any?): kotlin/Boolean // org.kotlincrypto.core/Counter.equals|equals(kotlin.Any?){}[0] final fun hashCode(): kotlin/Int // org.kotlincrypto.core/Counter.hashCode|hashCode(){}[0] final fun toString(): kotlin/String // org.kotlincrypto.core/Counter.toString|toString(){}[0] - abstract class Bit32 : org.kotlincrypto.core/Counter { // org.kotlincrypto.core/Counter.Bit32|null[0] + final class Bit32 : org.kotlincrypto.core/Counter { // org.kotlincrypto.core/Counter.Bit32|null[0] constructor (kotlin/Int) // org.kotlincrypto.core/Counter.Bit32.|(kotlin.Int){}[0] constructor (kotlin/Int, kotlin/Int, kotlin/Int) // org.kotlincrypto.core/Counter.Bit32.|(kotlin.Int;kotlin.Int;kotlin.Int){}[0] - constructor (org.kotlincrypto.core/Counter.Bit32) // org.kotlincrypto.core/Counter.Bit32.|(org.kotlincrypto.core.Counter.Bit32){}[0] final val incrementBy // org.kotlincrypto.core/Counter.Bit32.incrementBy|{}incrementBy[0] final fun (): kotlin/Int // org.kotlincrypto.core/Counter.Bit32.incrementBy.|(){}[0] @@ -52,8 +50,9 @@ sealed class org.kotlincrypto.core/Counter { // org.kotlincrypto.core/Counter|nu final var lo // org.kotlincrypto.core/Counter.Bit32.lo|{}lo[0] final fun (): kotlin/Int // org.kotlincrypto.core/Counter.Bit32.lo.|(){}[0] - open fun increment() // org.kotlincrypto.core/Counter.Bit32.increment|increment(){}[0] - open fun reset() // org.kotlincrypto.core/Counter.Bit32.reset|reset(){}[0] + final fun copy(): org.kotlincrypto.core/Counter.Bit32 // org.kotlincrypto.core/Counter.Bit32.copy|copy(){}[0] + final fun increment() // org.kotlincrypto.core/Counter.Bit32.increment|increment(){}[0] + final fun reset() // org.kotlincrypto.core/Counter.Bit32.reset|reset(){}[0] final object Companion { // org.kotlincrypto.core/Counter.Bit32.Companion|null[0] final const val MAX_INCREMENT // org.kotlincrypto.core/Counter.Bit32.Companion.MAX_INCREMENT|{}MAX_INCREMENT[0] @@ -61,10 +60,9 @@ sealed class org.kotlincrypto.core/Counter { // org.kotlincrypto.core/Counter|nu } } - abstract class Bit64 : org.kotlincrypto.core/Counter { // org.kotlincrypto.core/Counter.Bit64|null[0] + final class Bit64 : org.kotlincrypto.core/Counter { // org.kotlincrypto.core/Counter.Bit64|null[0] constructor (kotlin/Long) // org.kotlincrypto.core/Counter.Bit64.|(kotlin.Long){}[0] constructor (kotlin/Long, kotlin/Long, kotlin/Long) // org.kotlincrypto.core/Counter.Bit64.|(kotlin.Long;kotlin.Long;kotlin.Long){}[0] - constructor (org.kotlincrypto.core/Counter.Bit64) // org.kotlincrypto.core/Counter.Bit64.|(org.kotlincrypto.core.Counter.Bit64){}[0] final val incrementBy // org.kotlincrypto.core/Counter.Bit64.incrementBy|{}incrementBy[0] final fun (): kotlin/Long // org.kotlincrypto.core/Counter.Bit64.incrementBy.|(){}[0] @@ -74,8 +72,9 @@ sealed class org.kotlincrypto.core/Counter { // org.kotlincrypto.core/Counter|nu final var lo // org.kotlincrypto.core/Counter.Bit64.lo|{}lo[0] final fun (): kotlin/Long // org.kotlincrypto.core/Counter.Bit64.lo.|(){}[0] - open fun increment() // org.kotlincrypto.core/Counter.Bit64.increment|increment(){}[0] - open fun reset() // org.kotlincrypto.core/Counter.Bit64.reset|reset(){}[0] + final fun copy(): org.kotlincrypto.core/Counter.Bit64 // org.kotlincrypto.core/Counter.Bit64.copy|copy(){}[0] + final fun increment() // org.kotlincrypto.core/Counter.Bit64.increment|increment(){}[0] + final fun reset() // org.kotlincrypto.core/Counter.Bit64.reset|reset(){}[0] final object Companion { // org.kotlincrypto.core/Counter.Bit64.Companion|null[0] final const val MAX_INCREMENT // org.kotlincrypto.core/Counter.Bit64.Companion.MAX_INCREMENT|{}MAX_INCREMENT[0] diff --git a/library/core/src/commonMain/kotlin/org/kotlincrypto/core/Counter.kt b/library/core/src/commonMain/kotlin/org/kotlincrypto/core/Counter.kt index 7ae1c45..6538f3f 100644 --- a/library/core/src/commonMain/kotlin/org/kotlincrypto/core/Counter.kt +++ b/library/core/src/commonMain/kotlin/org/kotlincrypto/core/Counter.kt @@ -23,21 +23,28 @@ import kotlin.jvm.JvmName /** * Utility for counting things. * */ -public sealed class Counter private constructor() { +public sealed class Counter private constructor(): Resettable, Copyable { + + /** + * Increments the counter + * */ + public abstract fun increment() /** * A counter that utilizes 32-bit numbers providing a maximum count of 2^64. + * + * @see [Bit64] * */ - public abstract class Bit32: Counter { + public class Bit32: Counter { public companion object { /** * The maximum value for which [Bit32.incrementBy] can be set to. * - * 1024 * 1024 >> 1048576 + * 1024^2 >> 1048576 * */ - public const val MAX_INCREMENT: Int = 1024 * 1024 // Never decrease, only increase. + public const val MAX_INCREMENT: Int = 1048576 // Never decrease, only increase. } /** @@ -90,39 +97,40 @@ public sealed class Counter private constructor() { * */ public constructor(incrementBy: Int): this(0, 0, incrementBy) - /** - * Creates a clone of [other] - * */ - public constructor(other: Bit32): super() { - this.incrementBy = other.incrementBy - this.lo = other.lo - this.hi = other.hi - } + public override fun copy(): Bit32 = Bit32(this) - protected override fun increment() { + public override fun increment() { lo += incrementBy if (lo == 0) hi++ } - protected override fun reset() { + public override fun reset() { lo = 0 hi = 0 } + + private constructor(other: Bit32): super() { + this.incrementBy = other.incrementBy + this.lo = other.lo + this.hi = other.hi + } } /** * A counter that utilizes 64-bit numbers providing a maximum count of 2^128. + * + * @see [Bit32] * */ - public abstract class Bit64: Counter { + public class Bit64: Counter { public companion object { /** * The maximum value for which [Bit64.incrementBy] can be set to. * - * @see [Bit32.MAX_INCREMENT] + * 1024^4 >> 1099511627776 * */ - public const val MAX_INCREMENT: Long = Bit32.MAX_INCREMENT.toLong() + public const val MAX_INCREMENT: Long = 1099511627776L // Never decrease, only increase. } /** @@ -175,28 +183,24 @@ public sealed class Counter private constructor() { * */ public constructor(incrementBy: Long): this(0, 0, incrementBy) - /** - * Creates a clone of [other] - * */ - public constructor(other: Bit64): super() { - this.incrementBy = other.incrementBy - this.lo = other.lo - this.hi = other.hi - } + public override fun copy(): Bit64 = Bit64(this) - protected override fun increment() { + public override fun increment() { lo += incrementBy if (lo == 0L) hi++ } - protected override fun reset() { + public override fun reset() { lo = 0L hi = 0L } - } - protected abstract fun increment() - protected abstract fun reset() + private constructor(other: Bit64): super() { + this.incrementBy = other.incrementBy + this.lo = other.lo + this.hi = other.hi + } + } private val code = Any() diff --git a/library/core/src/commonTest/kotlin/org/kotlincrypto/core/CounterUnitTest.kt b/library/core/src/commonTest/kotlin/org/kotlincrypto/core/CounterUnitTest.kt index fc10257..7515499 100644 --- a/library/core/src/commonTest/kotlin/org/kotlincrypto/core/CounterUnitTest.kt +++ b/library/core/src/commonTest/kotlin/org/kotlincrypto/core/CounterUnitTest.kt @@ -24,50 +24,50 @@ class CounterUnitTest { @Test fun givenIncrementBy_when0_thenThrowsException() { assertFailsWith { - TestBit32Counter(0) + Counter.Bit32(0) } assertFailsWith { - TestBit64Counter(0) + Counter.Bit64(0) } } @Test fun givenIncrementBy_whenExceedsMaximum_thenThrowsException() { assertFailsWith { - TestBit32Counter(Counter.Bit32.MAX_INCREMENT + 8) + Counter.Bit32(Counter.Bit32.MAX_INCREMENT + 8) } assertFailsWith { - TestBit64Counter(Counter.Bit64.MAX_INCREMENT + 8) + Counter.Bit64(Counter.Bit64.MAX_INCREMENT + 8) } } @Test fun givenIncrementBy_whenNotFactory8_thenThrowsException() { assertFailsWith { - TestBit32Counter(9) + Counter.Bit32(9) } assertFailsWith { - TestBit64Counter(9) + Counter.Bit64(9) } } @Test fun givenLo_whenNotFactoryIncrementBy_thenThrowsException() { // Would throw if 24 was not a factor of 8... - TestBit32Counter(24) - TestBit64Counter(24) + Counter.Bit32(24) + Counter.Bit64(24) assertFailsWith { - TestBit32Counter(8, 0, 24) + Counter.Bit32(8, 0, 24) } assertFailsWith { - TestBit64Counter(16, 0, 24) + Counter.Bit64(16, 0, 24) } } @Test fun givenBit32_whenReset_thenIsZero() { - val c = TestBit32Counter(8, 8, 8) + val c = Counter.Bit32(8, 8, 8) assertEquals(8, c.lo) assertEquals(8, c.hi) assertEquals(8, c.incrementBy) @@ -78,7 +78,7 @@ class CounterUnitTest { @Test fun givenBit64_whenReset_thenIsZero() { - val c = TestBit64Counter(8, 8, 8) + val c = Counter.Bit64(8, 8, 8) assertEquals(8, c.lo) assertEquals(8, c.hi) assertEquals(8, c.incrementBy) @@ -89,7 +89,7 @@ class CounterUnitTest { @Test fun givenBit32_whenIncrement_thenIncrements() { - var c = TestBit32Counter(-16, 0, 8) + var c = Counter.Bit32(-16, 0, 8) c.increment() assertEquals(-8, c.lo) assertEquals(0, c.hi) @@ -97,7 +97,7 @@ class CounterUnitTest { assertEquals(0, c.lo) assertEquals(1, c.hi) - c = TestBit32Counter(Int.MAX_VALUE - 7, 0, 8) + c = Counter.Bit32(Int.MAX_VALUE - 7, 0, 8) c.increment() assertEquals(Int.MIN_VALUE, c.lo) assertEquals(0, c.hi) @@ -105,7 +105,7 @@ class CounterUnitTest { @Test fun givenBit64_whenIncrement_thenIncrements() { - var c = TestBit64Counter(-16, 0, 8) + var c = Counter.Bit64(-16, 0, 8) c.increment() assertEquals(-8, c.lo) assertEquals(0, c.hi) @@ -113,18 +113,27 @@ class CounterUnitTest { assertEquals(0, c.lo) assertEquals(1, c.hi) - c = TestBit64Counter(Long.MAX_VALUE - 7, 0, 8) + c = Counter.Bit64(Long.MAX_VALUE - 7, 0, 8) c.increment() assertEquals(Long.MIN_VALUE, c.lo) assertEquals(0, c.hi) } @Test - fun givenBit32_whenClone_thenCopiesValues() { - val expected = TestBit32Counter(8, 8, 8) - val actual = TestBit32Counter(expected) - assertEquals(expected.incrementBy, actual.incrementBy) - assertEquals(expected.lo, actual.lo) - assertEquals(expected.hi, actual.hi) + fun givenBit32_whenCopy_thenCopiesValues() { + val expected = Counter.Bit32(8, 8, 8) + val copy = expected.copy() + assertEquals(expected.incrementBy, copy.incrementBy) + assertEquals(expected.lo, copy.lo) + assertEquals(expected.hi, copy.hi) + } + + @Test + fun givenBit64_whenCopy_thenCopiesValues() { + val expected = Counter.Bit64(8, 8, 8) + val copy = expected.copy() + assertEquals(expected.incrementBy, copy.incrementBy) + assertEquals(expected.lo, copy.lo) + assertEquals(expected.hi, copy.hi) } } diff --git a/library/core/src/commonTest/kotlin/org/kotlincrypto/core/TestBit32Counter.kt b/library/core/src/commonTest/kotlin/org/kotlincrypto/core/TestBit32Counter.kt deleted file mode 100644 index 3105245..0000000 --- a/library/core/src/commonTest/kotlin/org/kotlincrypto/core/TestBit32Counter.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2025 Matthew Nelson - * - * 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 org.kotlincrypto.core - -class TestBit32Counter: Counter.Bit32 { - constructor(lo: Int, hi: Int, incrementBy: Int): super(lo, hi, incrementBy) - constructor(incrementBy: Int): super(incrementBy) - constructor(other: TestBit32Counter): super(other) - - public override fun increment() { super.increment() } - public override fun reset() { super.reset() } -} - -class TestBit64Counter: Counter.Bit64 { - constructor(lo: Long, hi: Long, incrementBy: Long): super(lo, hi, incrementBy) - constructor(incrementBy: Long): super(incrementBy) - constructor(other: TestBit64Counter): super(other) - - public override fun increment() { super.increment() } - public override fun reset() { super.reset() } -} From 898e6cdba3b9ec260cc7c2e96436b118f5c45347 Mon Sep 17 00:00:00 2001 From: Matthew Nelson Date: Thu, 2 Jan 2025 08:58:14 -0500 Subject: [PATCH 2/2] Improve copy test --- .../kotlin/org/kotlincrypto/core/CounterUnitTest.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/core/src/commonTest/kotlin/org/kotlincrypto/core/CounterUnitTest.kt b/library/core/src/commonTest/kotlin/org/kotlincrypto/core/CounterUnitTest.kt index 7515499..e185b65 100644 --- a/library/core/src/commonTest/kotlin/org/kotlincrypto/core/CounterUnitTest.kt +++ b/library/core/src/commonTest/kotlin/org/kotlincrypto/core/CounterUnitTest.kt @@ -18,6 +18,7 @@ package org.kotlincrypto.core import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertNotEquals class CounterUnitTest { @@ -123,17 +124,23 @@ class CounterUnitTest { fun givenBit32_whenCopy_thenCopiesValues() { val expected = Counter.Bit32(8, 8, 8) val copy = expected.copy() + assertNotEquals(expected, copy) assertEquals(expected.incrementBy, copy.incrementBy) assertEquals(expected.lo, copy.lo) assertEquals(expected.hi, copy.hi) + copy.increment() + assertNotEquals(expected.lo, copy.lo) } @Test fun givenBit64_whenCopy_thenCopiesValues() { val expected = Counter.Bit64(8, 8, 8) val copy = expected.copy() + assertNotEquals(expected, copy) assertEquals(expected.incrementBy, copy.incrementBy) assertEquals(expected.lo, copy.lo) assertEquals(expected.hi, copy.hi) + copy.increment() + assertNotEquals(expected.lo, copy.lo) } }