serializable and hashable BitArray. Comparable BitList. Small improvements

This commit is contained in:
Sergey Chernov 2025-09-26 19:45:28 +04:00
parent 2696f1546d
commit 3481a718b1
11 changed files with 80 additions and 14 deletions

View File

@ -21,10 +21,10 @@ import lyng.time
//
// After all optimizations it takes ~120ms.
//
//for( r in 1..100 ) {
// val start = Instant.now()
for( r in 1..100 ) {
val start = Instant.now()
val found = naiveCountHappyNumbers()
// println("Found happy numbers: %d time %s"(found, Instant.now() - start))
println("Found happy numbers: %d time %s"(found, Instant.now() - start))
assert( found == 55252 )
// delay(0.01)
//}
delay(0.1)
}

View File

@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
group = "net.sergeych"
version = "0.9.1-SNAPSHOT"
version = "0.9.2-SNAPSHOT"
buildscript {
repositories {
@ -66,6 +66,7 @@ kotlin {
// iosArm64()
// iosSimulatorArm64()
linuxX64()
linuxArm64()
js {
browser()
nodejs()
@ -79,9 +80,9 @@ kotlin {
sourceSets {
all {
languageSettings.optIn("kotlinx.coroutines.ExperimentalCoroutinesApi")
languageSettings.optIn("kotlin.contracts.ExperimentalContracts")
languageSettings.optIn("kotlin.ExperimentalUnsignedTypes")
languageSettings.optIn("kotlin.coroutines.DelicateCoroutinesApi")
languageSettings.optIn("kotlin.contracts.ExperimentalContracts")
languageSettings.optIn("kotlinx.coroutines.flow.DelicateCoroutinesApi")
}

View File

@ -164,6 +164,7 @@ class CompilerContext(val tokens: List<Token>) {
}
}
@Suppress("NOTHING_TO_INLINE")
inline fun addBreak() {
breakFound = true
}

View File

@ -26,6 +26,7 @@ import net.sergeych.lynon.ObjLynonClass
import net.sergeych.mp_tools.globalDefer
import kotlin.math.*
@Suppress("TYPE_INTERSECTION_AS_REIFIED_WARNING")
class Script(
override val pos: Pos,
private val statements: List<Statement> = emptyList(),

View File

@ -367,6 +367,7 @@ open class Obj {
}
@Suppress("NOTHING_TO_INLINE")
inline fun from(obj: Any?): Obj {
@Suppress("UNCHECKED_CAST")
return when (obj) {

View File

@ -35,12 +35,12 @@ class ObjBitBuffer(val bitArray: BitArray) : Obj() {
}.apply {
addFn("toBuffer") {
requireNoArgs()
ObjBuffer(thisAs<ObjBitBuffer>().bitArray.asUbyteArray())
ObjBuffer(thisAs<ObjBitBuffer>().bitArray.asUByteArray())
}
addFn("toDump") {
requireNoArgs()
ObjString(
thisAs<ObjBitBuffer>().bitArray.asUbyteArray().toDump()
thisAs<ObjBitBuffer>().bitArray.asUByteArray().toDump()
)
}
addFn("size") {

View File

@ -17,8 +17,10 @@
package net.sergeych.lynon
import kotlin.math.min
@Suppress("unused")
interface BitList {
interface BitList: Comparable<BitList> {
operator fun get(bitIndex: Long): Int
operator fun set(bitIndex: Long,value: Int)
val size: Long
@ -31,6 +33,22 @@ interface BitList {
if( index < size) this@BitList[index++]
else null
}
override fun compareTo(other: BitList): Int {
val m = min(size, other.size)
for( i in 0 ..< m) {
val a = this[i]
val b = other[i]
when {
a < b -> return -1
a > b -> return 1
}
}
if( size > other.size) return 1
if( size < other.size) return -1
return 0
}
}
fun bitListOf(vararg bits: Int): BitList {

View File

@ -17,13 +17,18 @@
package net.sergeych.lynon
import kotlinx.serialization.Serializable
import kotlin.math.min
/**
* BitList implementation as fixed suze array of bits; indexing works exactly same as if
* [MemoryBitInput] is used with [MemoryBitInput.getBit]. See [MemoryBitOutput] for
* bits order and more information.
*
* It is [BitList] - comparable, and provides valid [hashCode] and [equals], so it could
* also be used as a key in maps.
*/
@Serializable
class BitArray(val bytes: UByteArray, val lastByteBits: Int) : BitList {
val bytesSize: Int get() = bytes.size
@ -73,7 +78,15 @@ class BitArray(val bytes: UByteArray, val lastByteBits: Int) : BitList {
fun asByteArray(): ByteArray = bytes.asByteArray()
@Suppress("unused")
fun asUbyteArray(): UByteArray = bytes
fun asUByteArray(): UByteArray = bytes
override fun equals(other: Any?): Boolean {
return other is BitList && this.compareTo(other) == 0
}
override fun hashCode(): Int {
return bytes.contentHashCode()
}
companion object {

View File

@ -18,7 +18,6 @@
package net.sergeych.lynon
import net.sergeych.collections.SortedList
import net.sergeych.lynon.Huffman.Alphabet
/**
@ -285,7 +284,7 @@ object Huffman {
fun <T>decompress(bin: BitInput,alphabet: Alphabet<T>): UByteArray {
val codes = deserializeCanonicCodes(bin, alphabet)
return decompressUsingCodes(bin, codes, alphabet).asUbyteArray()
return decompressUsingCodes(bin, codes, alphabet).asUByteArray()
}
}

View File

@ -56,7 +56,7 @@ object ObjLynonClass : ObjClass("Lynon") {
@Suppress("unused")
suspend fun lynonEncodeAny(scope: Scope, value: Obj): UByteArray =
(ObjLynonClass.encodeAny(scope, value))
.bitArray.asUbyteArray()
.bitArray.asUByteArray()
@Suppress("unused")
suspend fun lynonDecodeAny(scope: Scope, encoded: UByteArray): Obj =

View File

@ -22,7 +22,10 @@ import net.sergeych.lyng.Source
import net.sergeych.lyng.eval
import net.sergeych.lyng.pacman.InlineSourcesImportProvider
import net.sergeych.lyng.toSource
import net.sergeych.lynon.BitArray
import net.sergeych.lynon.BitList
import kotlin.test.Test
import kotlin.test.assertNotEquals
class OtherTests {
@Test
@ -67,4 +70,33 @@ class OtherTests {
Unit
}
@Test
fun testBitArrayEqAndHash() {
val b1 = BitArray.ofBits(1, 0, 1, 1)
val b11 = BitArray.ofBits(1, 0, 1, 1)
val b2 = BitArray.ofBits(1, 1, 1, 1)
val b3 = BitArray.ofBits(1, 0, 1, 1, 0)
assert( b3 > b1 )
assert( b2 > b1)
assert( b11.compareTo(b1) == 0)
assertEquals(b1, b11)
assertNotEquals(b1, b2)
assertNotEquals(b1, b3)
assert( b1.hashCode() == b11.hashCode() )
val x = mutableMapOf<BitList,String>()
x[b1] = "wrong"
x[b11] = "OK"
x[b2] = "other"
assertEquals("OK", x[b11])
assertEquals("OK", x[b1])
assertEquals("other", x[b2])
}
}