- no caching on stored delegates, fix problens with memory storage connections

+ optStored now properly load/store only non-null values
* possible concurrent modification in KVStorage.clear fixed
This commit is contained in:
sergeych committed 2024-11-30 13:37:20 +07:00
1 parent 2eb38e27ed
commit d29bf960aa
4 files changed
+86 -42

No files matched your search

@@ -1,11 +1,10 @@
package net.sergeych.bintools
import kotlinx.serialization.KSerializer
import kotlinx.serialization.serializer
import net.sergeych.bipack.BipackDecoder
import net.sergeych.bipack.BipackEncoder
import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
@@ -43,7 +42,7 @@ interface KVStorage {
* Default implementation uses [keys]. You may override it for performance
*/
fun clear() {
for (k in keys) this[k] = null
for (k in keys.toList()) this[k] = null
}
/**
@@ -93,46 +92,50 @@ inline fun <reified T:Any>KVStorage.read(key: String): T? =
@Suppress("unused")
inline fun <reified T:Any>KVStorage.load(key: String): T? = read(key)
inline operator fun <reified T> KVStorage.invoke(defaultValue: T,overrideName: String? = null) =
KVStorageDelegate<T>(this, typeOf<T>(), defaultValue, overrideName)
inline operator fun <reified T: Any> KVStorage.invoke(defaultValue: T,overrideName: String? = null) =
KVStorageDelegate(this, serializer<T>(), defaultValue, overrideName)
inline fun <reified T> KVStorage.stored(defaultValue: T, overrideName: String? = null) =
KVStorageDelegate<T>(this, typeOf<T>(), defaultValue, overrideName)
inline fun <reified T: Any> KVStorage.stored(defaultValue: T, overrideName: String? = null) =
KVStorageDelegate(this, serializer<T>(), defaultValue, overrideName)
inline fun <reified T> KVStorage.optStored(overrideName: String? = null) =
KVStorageDelegate<T?>(this, typeOf<T?>(), null, overrideName)
inline fun <reified T: Any> KVStorage.optStored(overrideName: String? = null) =
KVStorageOptDelegate<T>(this, serializer<T>(),overrideName)
class KVStorageDelegate<T>(
class KVStorageDelegate<T: Any>(
private val storage: KVStorage,
type: KType,
private val serializer: KSerializer<T>,
private val defaultValue: T,
private val overrideName: String? = null,
) {
private fun name(property: KProperty<*>): String = overrideName ?: property.name
private var cachedValue: T = defaultValue
private var cacheReady = false
private val serializer = serializer(type)
operator fun getValue(thisRef: Any?, property: KProperty<*>): T =
storage.get(name(property))?.let { BipackDecoder.decode(serializer, it) }
?: defaultValue
@Suppress("UNCHECKED_CAST")
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
if (cacheReady) return cachedValue
val data = storage.get(name(property))
if (data == null)
cachedValue = defaultValue
else
cachedValue = BipackDecoder.decode(data.toDataSource(), serializer) as T
cacheReady = true
return cachedValue
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
// if (!cacheReady || value != cachedValue) {
cachedValue = value
cacheReady = true
storage[name(property)] = BipackEncoder.encode(serializer, value)
}
}
class KVStorageOptDelegate<T: Any>(
private val storage: KVStorage,
private val serializer: KSerializer<T>,
private val overrideName: String? = null,
) {
private fun name(property: KProperty<*>): String = overrideName ?: property.name
operator fun getValue(thisRef: Any?, property: KProperty<*>): T? =
storage.get(name(property))?.let{
BipackDecoder.decode(serializer, it)
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
if (value == null)
storage.delete(name(property))
else
storage[name(property)] = BipackEncoder.encode(serializer, value)
// }
}
}