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
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.decodeFromJsonElement
@Serializable
@SerialName("TGeoManager")
public class TGeoManager : TNamed() {
@Contextual
public val fMatrices: TObjArray = TObjArray.empty
@Contextual
public val fShapes: TObjArray = TObjArray.empty
@Contextual
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
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -30,11 +31,12 @@ public class TGeoTranslation(
@SerialName("TGeoRotation")
public class TGeoRotation(
public val fRotationMatrix: DoubleArray
): TGeoMatrix()
) : TGeoMatrix()
@Serializable
@SerialName("TGeoCombiTrans")
public class TGeoCombiTrans(
public val fTranslation: DoubleArray,
@Contextual
public val fRotation: TGeoRotation? = null,
): TGeoMatrix()
) : TGeoMatrix()

View File

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

View File

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

View File

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

View File

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

View File

@ -10,15 +10,23 @@ public abstract class TObject {
}
@Serializable
public abstract class TNamed : TObject() {
public open class TNamed : TObject() {
public val fName: String = ""
public val fTitle: String = ""
}
@Serializable
@SerialName("TObjArray")
public class TObjArray(public val arr: List<TObject>){
public class TObjArray(public val arr: List<TObject>): TObject() {
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
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.*
import kotlinx.serialization.modules.PolymorphicModuleBuilder
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
import kotlinx.serialization.modules.*
import kotlin.reflect.KClass
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>(
private val refCache: RefCache,
private val tSerializer: KSerializer<T>
) : KSerializer<T> {
public fun TObject.Companion.decodeFromString(serializer: KSerializer<out TObject>, string: String): TObject {
val json = RootDecoder.json.parseToJsonElement(string)
return RootDecoder.decode(serializer, json)
}
override val descriptor: SerialDescriptor get() = tSerializer.descriptor
private object RootDecoder {
override fun deserialize(decoder: Decoder): T {
val input = decoder as JsonDecoder
val element = input.decodeJsonElement()
val refId = (element as? JsonObject)?.get("\$ref")?.jsonPrimitive?.int
return if (refId != null) {
//Do unref
val refValue = refCache[refId]
refValue as T //TODO research means to make it safe
} else {
val res = input.json.decodeFromJsonElement(tSerializer, element)
//val uid = res.fUniqueID
refCache.add(res)
res
private class RootUnrefSerializer<T>(
private val tSerializer: KSerializer<T>,
private val refCache: MutableList<RefEntry>,// = ArrayList<RefEntry>(4096)
private val counter: ReferenceCounter
) : KSerializer<T> by tSerializer {
override fun deserialize(decoder: Decoder): T {
val input = decoder as JsonDecoder
val element = input.decodeJsonElement()
val refId = (element as? JsonObject)?.get("\$ref")?.jsonPrimitive?.int
val ref = if (refId != null) {
//Do unref
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) {
tSerializer.serialize(encoder, value)
private fun <T> KSerializer<T>.unref(refCache: MutableList<RefEntry>, counter: ReferenceCounter): KSerializer<T> =
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)
}
}
private fun <T : TObject> KSerializer<T>.unref(refCache: RefCache): RootJsonSerializer<T> =
RootJsonSerializer(refCache, this)
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 {
/**
* Create an instance of Json with unfolding Root references. This instance could not be reused because of the cache.
*/
private fun unrefJson(refCache: MutableList<RefEntry>, counter: ReferenceCounter): Json = Json {
encodeDefaults = true
ignoreUnknownKeys = true
classDiscriminator = "_typename"
serializersModule = SerializersModule {
polymorphic(TGeoShape::class) {
default { TGeoBBox.serializer().unref(refCache) }
shapes(refCache)
}
serializersModule = unrefSerializersModule(refCache, counter)
}
polymorphic(TGeoMatrix::class) {
matrices(refCache)
}
polymorphic(TObject::class) {
shapes(refCache)
matrices(refCache)
fun decode(sourceDeserializer: KSerializer<out TObject>, source: JsonElement): TObject {
val counter = ReferenceCounter()
val refCache = ArrayList<RefEntry>()
subclass(TGeoMaterial.serializer().unref(refCache))
subclass(TGeoMixture.serializer().unref(refCache))
subclass(TGeoMedium.serializer().unref(refCache))
subclass(TGeoNode.serializer().unref(refCache))
subclass(TGeoNodeMatrix.serializer().unref(refCache))
subclass(TGeoVolume.serializer().unref(refCache))
subclass(TGeoVolumeAssembly.serializer().unref(refCache))
}
polymorphic(TGeoNode::class, TGeoNode.serializer().unref(refCache)) {
subclass(TGeoNodeMatrix.serializer().unref(refCache))
}
polymorphic(TGeoVolume::class, TGeoVolume.serializer().unref(refCache)) {
subclass(TGeoVolumeAssembly.serializer().unref(refCache))
fun fillCache(element: JsonElement) {
when (element) {
is JsonObject -> {
if (element["_typename"] != null) {
refCache.add(RefEntry(element))
}
element.values.forEach {
fillCache(it)
}
}
is JsonArray -> {
element.forEach {
fillCache(it)
}
}
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
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() {
val string = TGeoManager::class.java.getResourceAsStream("/BM@N.root.json")!!
.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)
}