refs #35 caching moved to level above objec serializing so we can cache strings, etc that are not Obj instances

This commit is contained in:
sergeych committed 2025-07-12 11:48:14 +03:00
1 parent f26ee7cd7c
commit 77f9191387
7 files changed
+78 -59

No files matched your search

@@ -4,27 +4,31 @@ import net.sergeych.lyng.Scope
import net.sergeych.lyng.obj.Obj
import net.sergeych.lyng.obj.ObjClass
open class LynonDecoder(private val bin: BitInput) {
open class LynonDecoder(val bin: BitInput) {
val cache = mutableListOf<Obj>()
fun unpackObject(scope: Scope, type: ObjClass): Obj {
inline fun decodeCached(f: LynonDecoder.() -> Obj): Obj {
return if( bin.getBit() == 0 ) {
// unpack and cache
val cached = bin.getBool()
type.deserialize(scope, this).also {
f().also {
if( cached ) cache.add(it)
}
}
else {
// get cache reference
val size = sizeInBits(cache.size)
val id = bin.getBitsOrNull(size)?.toInt() ?: scope.raiseError("Invalid object id: unexpected end of stream")
if( id >= cache.size ) scope.raiseError("Invalid object id: $id should be in 0..<${cache.size}")
val id = bin.getBitsOrNull(size)?.toInt() ?: throw RuntimeException("Invalid object id: unexpected end of stream")
if( id >= cache.size ) throw RuntimeException("Invalid object id: $id should be in 0..<${cache.size}")
cache[id]
}
}
fun unpackObject(scope: Scope, type: ObjClass): Obj {
return decodeCached { type.deserialize(scope, this) }
}
fun unpackBinaryData(): ByteArray? {
val size = bin.unpackUnsigned()
return bin.getBytes(size.toInt())
@@ -6,13 +6,13 @@ import net.sergeych.lyng.obj.ObjBool
import net.sergeych.lyng.obj.ObjChar
import net.sergeych.lyng.obj.ObjInt
class LynonPacker(private val bout: MemoryBitOutput= MemoryBitOutput()) : LynonEncoder(bout) {
fun toUByteArray(): UByteArray = bout.toUByteArray()
class LynonPacker(bout: MemoryBitOutput = MemoryBitOutput()) : LynonEncoder(bout) {
fun toUByteArray(): UByteArray = (bout as MemoryBitOutput).toUByteArray()
}
class LynonUnpacker(source: UByteArray) : LynonDecoder(MemoryBitInput(source))
open class LynonEncoder(private val bout: BitOutput) {
open class LynonEncoder(val bout: BitOutput) {
fun shouldCache(obj: Obj): Boolean = when (obj) {
is ObjChar -> false
@@ -21,41 +21,56 @@ open class LynonEncoder(private val bout: BitOutput) {
else -> true
}
val cache = mutableMapOf<Obj,Int>()
val cache = mutableMapOf<Any, Int>()
suspend fun packObject(scope: Scope,obj: Obj) {
cache[obj]?.let { cacheId ->
val size = sizeInBits(cache.size)
bout.putBit(1)
bout.putBits(cacheId, size)
} ?: run {
bout.putBit(0)
if( shouldCache(obj) ) {
inline fun encodeCached(item: Any, packer: LynonEncoder.() -> Unit) {
if (item is Obj) {
cache[item]?.let { cacheId ->
val size = sizeInBits(cache.size)
bout.putBit(1)
cache[obj] = cache.size
}
else
bout.putBits(cacheId.toULong(), size)
} ?: run {
bout.putBit(0)
if (shouldCache(item)) {
bout.putBit(1)
cache[item] = cache.size
} else
bout.putBit(0)
packer()
}
}
}
suspend fun encodeObj(scope: Scope, obj: Obj) {
encodeCached(obj) {
obj.serialize(scope, this)
}
}
fun packBinaryData(data: ByteArray) {
fun encodeBinaryData(data: ByteArray) {
bout.packUnsigned(data.size.toULong())
bout.putBytes(data)
}
fun packSigned(value: Long) { bout.packSigned(value) }
@Suppress("unused")
fun packUnsigned(value: ULong) { bout.packUnsigned(value) }
fun encodeSigned(value: Long) {
bout.packSigned(value)
}
@Suppress("unused")
fun packBool(value: Boolean) { bout.putBit(if (value) 1 else 0) }
fun packReal(value: Double) {
fun encodeUnsigned(value: ULong) {
bout.packUnsigned(value)
}
@Suppress("unused")
fun encodeBool(value: Boolean) {
bout.putBit(if (value) 1 else 0)
}
fun encodeReal(value: Double) {
bout.putBits(value.toRawBits().toULong(), 64)
}
fun packBoolean(value: Boolean) {
fun encodeBoolean(value: Boolean) {
bout.putBit(if (value) 1 else 0)
}