WIP root unref

This commit is contained in:
Alexander Nozik 2021-08-22 22:39:47 +03:00
parent 1b2d61008f
commit 64e084dc53
9 changed files with 286 additions and 108 deletions

View File

@ -1,29 +1,19 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.decodeFromJsonElement
@Serializable @Serializable
@SerialName("TGeoManager") @SerialName("TGeoManager")
public class TGeoManager : TNamed() { public class TGeoManager : TNamed() {
@Contextual
public val fMatrices: TObjArray = TObjArray.empty public val fMatrices: TObjArray = TObjArray.empty
@Contextual
public val fShapes: TObjArray = TObjArray.empty public val fShapes: TObjArray = TObjArray.empty
@Contextual
public val fVolumes: TObjArray = TObjArray.empty public val fVolumes: TObjArray = TObjArray.empty
public companion object {
/**
* Load Json encoded TGeoManager
*/
public fun decodeFromJson(jsonElement: JsonElement): TGeoManager =
rootJson().decodeFromJsonElement(jsonElement)
public fun decodeFromString(string: String): TGeoManager =
rootJson().decodeFromString(serializer(), string)
}
} }

View File

@ -1,5 +1,6 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -30,11 +31,12 @@ public class TGeoTranslation(
@SerialName("TGeoRotation") @SerialName("TGeoRotation")
public class TGeoRotation( public class TGeoRotation(
public val fRotationMatrix: DoubleArray public val fRotationMatrix: DoubleArray
): TGeoMatrix() ) : TGeoMatrix()
@Serializable @Serializable
@SerialName("TGeoCombiTrans") @SerialName("TGeoCombiTrans")
public class TGeoCombiTrans( public class TGeoCombiTrans(
public val fTranslation: DoubleArray, public val fTranslation: DoubleArray,
@Contextual
public val fRotation: TGeoRotation? = null, public val fRotation: TGeoRotation? = null,
): TGeoMatrix() ) : TGeoMatrix()

View File

@ -1,12 +1,14 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
@SerialName("TGeoMedium") @SerialName("TGeoMedium")
public class TGeoMedium( public class TGeoMedium(
public val fId : Int, public val fId: Int,
@Contextual
public val fMaterial: TGeoMaterial, public val fMaterial: TGeoMaterial,
public val fParams: DoubleArray public val fParams: DoubleArray
): TNamed() ) : TNamed()

View File

@ -1,5 +1,6 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -7,7 +8,10 @@ import kotlinx.serialization.Serializable
@SerialName("TGeoNode") @SerialName("TGeoNode")
public open class TGeoNode : TNamed() { public open class TGeoNode : TNamed() {
//val fGeoAtt: UInt //val fGeoAtt: UInt
@Contextual
public val fVolume: TGeoVolume? = null public val fVolume: TGeoVolume? = null
@Contextual
public val fMother: TGeoVolume? = null public val fMother: TGeoVolume? = null
public val fNumber: Int = 0 public val fNumber: Int = 0
public val fNovlp: Int = 0 public val fNovlp: Int = 0
@ -17,5 +21,6 @@ public open class TGeoNode : TNamed() {
@Serializable @Serializable
@SerialName("TGeoNodeMatrix") @SerialName("TGeoNodeMatrix")
public class TGeoNodeMatrix : TGeoNode() { public class TGeoNodeMatrix : TGeoNode() {
@Contextual
public val fMatrix: TGeoMatrix? = null public val fMatrix: TGeoMatrix? = null
} }

View File

@ -1,5 +1,6 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -22,36 +23,55 @@ public open class TGeoBBox : TGeoShape() {
@Serializable @Serializable
@SerialName("TGeoBoolNode") @SerialName("TGeoBoolNode")
public sealed class TGeoBoolNode : TObject() { public sealed class TGeoBoolNode : TObject() {
@Contextual
public abstract val fLeft: TGeoShape public abstract val fLeft: TGeoShape
@Contextual
public abstract val fLeftMat: TGeoMatrix public abstract val fLeftMat: TGeoMatrix
@Contextual
public abstract val fRight: TGeoShape public abstract val fRight: TGeoShape
@Contextual
public abstract val fRightMat: TGeoMatrix public abstract val fRightMat: TGeoMatrix
} }
@Serializable @Serializable
@SerialName("TGeoUnion") @SerialName("TGeoUnion")
public class TGeoUnion( public class TGeoUnion(
@Contextual
override val fLeft: TGeoShape, override val fLeft: TGeoShape,
@Contextual
override val fLeftMat: TGeoMatrix, override val fLeftMat: TGeoMatrix,
@Contextual
override val fRight: TGeoShape, override val fRight: TGeoShape,
@Contextual
override val fRightMat: TGeoMatrix override val fRightMat: TGeoMatrix
) : TGeoBoolNode() ) : TGeoBoolNode()
@Serializable @Serializable
@SerialName("TGeoSubtraction") @SerialName("TGeoSubtraction")
public class TGeoSubtraction( public class TGeoSubtraction(
@Contextual
override val fLeft: TGeoShape, override val fLeft: TGeoShape,
@Contextual
override val fLeftMat: TGeoMatrix, override val fLeftMat: TGeoMatrix,
@Contextual
override val fRight: TGeoShape, override val fRight: TGeoShape,
@Contextual
override val fRightMat: TGeoMatrix override val fRightMat: TGeoMatrix
) : TGeoBoolNode() ) : TGeoBoolNode()
@Serializable @Serializable
@SerialName("TGeoIntersection") @SerialName("TGeoIntersection")
public class TGeoIntersection( public class TGeoIntersection(
@Contextual
override val fLeft: TGeoShape, override val fLeft: TGeoShape,
@Contextual
override val fLeftMat: TGeoMatrix, override val fLeftMat: TGeoMatrix,
@Contextual
override val fRight: TGeoShape, override val fRight: TGeoShape,
@Contextual
override val fRightMat: TGeoMatrix override val fRightMat: TGeoMatrix
) : TGeoBoolNode() ) : TGeoBoolNode()
@ -103,6 +123,7 @@ public class TGeoTubeSeg(
@Serializable @Serializable
@SerialName("TGeoShapeAssembly") @SerialName("TGeoShapeAssembly")
public class TGeoShapeAssembly( public class TGeoShapeAssembly(
@Contextual
public val fVolume: TGeoVolumeAssembly, public val fVolume: TGeoVolumeAssembly,
public val fBBoxOK: Boolean = true public val fBBoxOK: Boolean = true
) : TGeoBBox() ) : TGeoBBox()

View File

@ -1,20 +1,30 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
@SerialName("TGeoVolume") @SerialName("TGeoVolume")
public open class TGeoVolume : TNamed(){ public open class TGeoVolume : TNamed() {
// "fGeoAtt" : 3084, // "fGeoAtt" : 3084,
// "fLineColor" : 3, // "fLineColor" : 3,
// "fLineStyle" : 1, // "fLineStyle" : 1,
// "fLineWidth" : 1, // "fLineWidth" : 1,
// "fFillColor" : 19, // "fFillColor" : 19,
// "fFillStyle" : 1001, // "fFillStyle" : 1001,
@Contextual
public lateinit var fNodes: TObjArray public lateinit var fNodes: TObjArray
internal set
@Contextual
public lateinit var fShape: TGeoShape public lateinit var fShape: TGeoShape
internal set
@Contextual
public lateinit var fMedium: TGeoMedium public lateinit var fMedium: TGeoMedium
internal set
public val fNumber: Int = 1 public val fNumber: Int = 1
public val fNtotal: Int = 1 public val fNtotal: Int = 1
public val fRefCount: Int = 1 public val fRefCount: Int = 1

View File

@ -10,15 +10,23 @@ public abstract class TObject {
} }
@Serializable @Serializable
public abstract class TNamed : TObject() { public open class TNamed : TObject() {
public val fName: String = "" public val fName: String = ""
public val fTitle: String = "" public val fTitle: String = ""
} }
@Serializable @Serializable
@SerialName("TObjArray") @SerialName("TObjArray")
public class TObjArray(public val arr: List<TObject>){ public class TObjArray(public val arr: List<TObject>): TObject() {
public companion object{ public companion object{
public val empty = TObjArray(emptyList()) public val empty: TObjArray = TObjArray(emptyList())
} }
} }
@Serializable
@SerialName("TList")
public class TList(public val arr: List<TObject>): TObject()
@Serializable
@SerialName("THashList")
public class THashList(public val arr: List<TObject>): TObject()

View File

@ -1,107 +1,223 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import kotlinx.serialization.modules.PolymorphicModuleBuilder import kotlinx.serialization.modules.*
import kotlinx.serialization.modules.SerializersModule import kotlin.reflect.KClass
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
private typealias RefCache = MutableList<TObject> /**
* Load Json encoded TObject
*/
public fun TObject.Companion.decodeFromJson(serializer: KSerializer<out TObject>, jsonElement: JsonElement): TObject =
RootDecoder.decode(serializer, jsonElement)
private class RootJsonSerializer<T : TObject>( public fun TObject.Companion.decodeFromString(serializer: KSerializer<out TObject>, string: String): TObject {
private val refCache: RefCache, val json = RootDecoder.json.parseToJsonElement(string)
private val tSerializer: KSerializer<T> return RootDecoder.decode(serializer, json)
) : KSerializer<T> { }
override val descriptor: SerialDescriptor get() = tSerializer.descriptor private object RootDecoder {
override fun deserialize(decoder: Decoder): T { private class RootUnrefSerializer<T>(
val input = decoder as JsonDecoder private val tSerializer: KSerializer<T>,
val element = input.decodeJsonElement() private val refCache: MutableList<RefEntry>,// = ArrayList<RefEntry>(4096)
val refId = (element as? JsonObject)?.get("\$ref")?.jsonPrimitive?.int private val counter: ReferenceCounter
return if (refId != null) { ) : KSerializer<T> by tSerializer {
//Do unref
val refValue = refCache[refId] override fun deserialize(decoder: Decoder): T {
refValue as T //TODO research means to make it safe val input = decoder as JsonDecoder
} else { val element = input.decodeJsonElement()
val res = input.json.decodeFromJsonElement(tSerializer, element) val refId = (element as? JsonObject)?.get("\$ref")?.jsonPrimitive?.int
//val uid = res.fUniqueID val ref = if (refId != null) {
refCache.add(res) //Do unref
res refCache[refId]
} else {
refCache[counter.value].also {
counter.increment()
}
}
return ref.value(tSerializer) as T //TODO research means to make it safe
} }
} }
override fun serialize(encoder: Encoder, value: T) { private fun <T> KSerializer<T>.unref(refCache: MutableList<RefEntry>, counter: ReferenceCounter): KSerializer<T> =
tSerializer.serialize(encoder, value) RootUnrefSerializer(this, refCache, counter)
@OptIn(ExperimentalSerializationApi::class)
fun unrefSerializersModule(
refCache: MutableList<RefEntry>, counter: ReferenceCounter
): SerializersModule = SerializersModule {
val collector = this
val unrefCollector = object : SerializersModuleCollector {
override fun <T : Any> contextual(
kClass: KClass<T>,
provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>
) {
collector.contextual(kClass) { provider(it).unref(refCache, counter) }
}
override fun <Base : Any, Sub : Base> polymorphic(
baseClass: KClass<Base>,
actualClass: KClass<Sub>,
actualSerializer: KSerializer<Sub>
) {
collector.polymorphic(baseClass, actualClass, actualSerializer.unref(refCache, counter))
}
override fun <Base : Any> polymorphicDefault(
baseClass: KClass<Base>,
defaultSerializerProvider: (className: String?) -> DeserializationStrategy<out Base>?
) {
collector.polymorphicDefault(baseClass) {
(defaultSerializerProvider(it) as KSerializer<out Base>).unref(refCache, counter)
}
}
}
serializersModule.dumpTo(unrefCollector)
} }
} /**
* Create an instance of Json with unfolding Root references. This instance could not be reused because of the cache.
private fun <T : TObject> KSerializer<T>.unref(refCache: RefCache): RootJsonSerializer<T> = */
RootJsonSerializer(refCache, this) private fun unrefJson(refCache: MutableList<RefEntry>, counter: ReferenceCounter): Json = Json {
private fun PolymorphicModuleBuilder<TGeoShape>.shapes(refCache: RefCache) {
subclass(TGeoBBox.serializer().unref(refCache))
subclass(TGeoCompositeShape.serializer().unref(refCache))
subclass(TGeoXtru.serializer().unref(refCache))
subclass(TGeoTube.serializer().unref(refCache))
subclass(TGeoTubeSeg.serializer().unref(refCache))
subclass(TGeoShapeAssembly.serializer().unref(refCache))
}
private fun PolymorphicModuleBuilder<TGeoMatrix>.matrices(refCache: RefCache) {
subclass(TGeoIdentity.serializer().unref(refCache))
subclass(TGeoHMatrix.serializer().unref(refCache))
subclass(TGeoTranslation.serializer().unref(refCache))
subclass(TGeoRotation.serializer().unref(refCache))
subclass(TGeoCombiTrans.serializer().unref(refCache))
}
/**
* Create an instance of Json with unfolding Root references. This instance could not be reused because of the cache.
*/
internal fun rootJson(): Json {
val refCache = ArrayList<TObject>(4096)
return Json {
encodeDefaults = true encodeDefaults = true
ignoreUnknownKeys = true ignoreUnknownKeys = true
classDiscriminator = "_typename" classDiscriminator = "_typename"
serializersModule = SerializersModule { serializersModule = unrefSerializersModule(refCache, counter)
polymorphic(TGeoShape::class) { }
default { TGeoBBox.serializer().unref(refCache) }
shapes(refCache)
}
polymorphic(TGeoMatrix::class) {
matrices(refCache)
}
polymorphic(TObject::class) { fun decode(sourceDeserializer: KSerializer<out TObject>, source: JsonElement): TObject {
shapes(refCache) val counter = ReferenceCounter()
matrices(refCache) val refCache = ArrayList<RefEntry>()
subclass(TGeoMaterial.serializer().unref(refCache)) fun fillCache(element: JsonElement) {
subclass(TGeoMixture.serializer().unref(refCache)) when (element) {
is JsonObject -> {
subclass(TGeoMedium.serializer().unref(refCache)) if (element["_typename"] != null) {
refCache.add(RefEntry(element))
subclass(TGeoNode.serializer().unref(refCache)) }
subclass(TGeoNodeMatrix.serializer().unref(refCache)) element.values.forEach {
subclass(TGeoVolume.serializer().unref(refCache)) fillCache(it)
subclass(TGeoVolumeAssembly.serializer().unref(refCache)) }
} }
polymorphic(TGeoNode::class, TGeoNode.serializer().unref(refCache)) { is JsonArray -> {
subclass(TGeoNodeMatrix.serializer().unref(refCache)) element.forEach {
} fillCache(it)
polymorphic(TGeoVolume::class, TGeoVolume.serializer().unref(refCache)) { }
subclass(TGeoVolumeAssembly.serializer().unref(refCache)) }
else -> {
}
} }
} }
fillCache(source)
return unrefJson(refCache, counter).decodeFromJsonElement(sourceDeserializer.unref(refCache, counter), source)
} }
class ReferenceCounter(var value: Int = 0) {
fun increment() {
value += 1
}
override fun toString(): String = value.toString()
}
class RefEntry(val obj: JsonObject) {
private var cachedValue: Any? = null
fun value(serializer: KSerializer<*>): Any {
if (cachedValue == null) {
cachedValue = json.decodeFromJsonElement(serializer, obj)
}
return cachedValue!!
}
override fun toString(): String = obj.toString()
}
private fun PolymorphicModuleBuilder<TGeoShape>.shapes() {
subclass(TGeoBBox.serializer())
subclass(TGeoCompositeShape.serializer())
subclass(TGeoXtru.serializer())
subclass(TGeoTube.serializer())
subclass(TGeoTubeSeg.serializer())
subclass(TGeoShapeAssembly.serializer())
}
private fun PolymorphicModuleBuilder<TGeoMatrix>.matrices() {
subclass(TGeoIdentity.serializer())
subclass(TGeoHMatrix.serializer())
subclass(TGeoTranslation.serializer())
subclass(TGeoRotation.serializer())
subclass(TGeoCombiTrans.serializer())
}
private fun PolymorphicModuleBuilder<TGeoBoolNode>.boolNodes() {
subclass(TGeoIntersection.serializer())
subclass(TGeoUnion.serializer())
subclass(TGeoSubtraction.serializer())
}
private val serializersModule = SerializersModule {
contextual(TGeoManager::class) { TGeoManager.serializer() }
contextual(TObjArray::class) { TObjArray.serializer() }
contextual(TGeoVolumeAssembly::class) { TGeoVolumeAssembly.serializer() }
contextual(TGeoShapeAssembly::class) { TGeoShapeAssembly.serializer() }
contextual(TGeoRotation::class) { TGeoRotation.serializer() }
contextual(TGeoMedium::class) { TGeoMedium.serializer() }
polymorphic(TGeoShape::class) {
default { TGeoBBox.serializer() }
shapes()
}
polymorphic(TGeoMatrix::class) {
matrices()
}
polymorphic(TGeoBoolNode::class) {
boolNodes()
}
polymorphic(TObject::class) {
subclass(TObjArray.serializer())
shapes()
matrices()
boolNodes()
subclass(TGeoMaterial.serializer())
subclass(TGeoMixture.serializer())
subclass(TGeoMedium.serializer())
subclass(TGeoNode.serializer())
subclass(TGeoNodeMatrix.serializer())
subclass(TGeoVolume.serializer())
subclass(TGeoVolumeAssembly.serializer())
}
polymorphic(TGeoNode::class, TGeoNode.serializer()) {
subclass(TGeoNodeMatrix.serializer())
}
polymorphic(TGeoVolume::class, TGeoVolume.serializer()) {
subclass(TGeoVolumeAssembly.serializer())
}
}
val json = Json {
encodeDefaults = true
ignoreUnknownKeys = true
classDiscriminator = "_typename"
serializersModule = this@RootDecoder.serializersModule
}
} }

View File

@ -1,7 +1,31 @@
package ru.mipt.npm.root package ru.mipt.npm.root
import kotlinx.serialization.json.*
private fun JsonElement.countTypes(): Sequence<String> = sequence {
val json = this@countTypes
when (json){
is JsonObject -> {
json["_typename"]?.let { yield(it.jsonPrimitive.content) }
json.values.forEach { yieldAll(it.countTypes()) }
}
is JsonArray -> {
json.forEach {
yieldAll(it.countTypes())
}
}
else -> {}
}
}
fun main() { fun main() {
val string = TGeoManager::class.java.getResourceAsStream("/BM@N.root.json")!! val string = TGeoManager::class.java.getResourceAsStream("/BM@N.root.json")!!
.readAllBytes().decodeToString() .readAllBytes().decodeToString()
val geo = TGeoManager.decodeFromString(string) val json = Json.parseToJsonElement(string)
val sizes = json.countTypes().groupBy { it }.mapValues { it.value.size }
sizes.forEach {
println(it)
}
val geo = TObject.decodeFromString(TGeoManager.serializer(), string)
} }