WIP root unref
This commit is contained in:
parent
1b2d61008f
commit
64e084dc53
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package ru.mipt.npm.root
|
||||
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@ -36,5 +37,6 @@ public class TGeoRotation(
|
||||
@SerialName("TGeoCombiTrans")
|
||||
public class TGeoCombiTrans(
|
||||
public val fTranslation: DoubleArray,
|
||||
@Contextual
|
||||
public val fRotation: TGeoRotation? = null,
|
||||
) : TGeoMatrix()
|
@ -1,5 +1,6 @@
|
||||
package ru.mipt.npm.root
|
||||
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@ -7,6 +8,7 @@ import kotlinx.serialization.Serializable
|
||||
@SerialName("TGeoMedium")
|
||||
public class TGeoMedium(
|
||||
public val fId: Int,
|
||||
@Contextual
|
||||
public val fMaterial: TGeoMaterial,
|
||||
public val fParams: DoubleArray
|
||||
) : TNamed()
|
@ -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
|
||||
}
|
@ -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()
|
@ -1,5 +1,6 @@
|
||||
package ru.mipt.npm.root
|
||||
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@ -12,9 +13,18 @@ public open class TGeoVolume : TNamed(){
|
||||
// "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
|
||||
|
@ -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()
|
@ -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 {
|
||||
|
||||
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
|
||||
return if (refId != null) {
|
||||
val ref = if (refId != null) {
|
||||
//Do unref
|
||||
val refValue = refCache[refId]
|
||||
refValue as T //TODO research means to make it safe
|
||||
refCache[refId]
|
||||
} else {
|
||||
val res = input.json.decodeFromJsonElement(tSerializer, element)
|
||||
//val uid = res.fUniqueID
|
||||
refCache.add(res)
|
||||
res
|
||||
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))
|
||||
}
|
||||
|
||||
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))
|
||||
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)
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
serializersModule.dumpTo(unrefCollector)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
private fun unrefJson(refCache: MutableList<RefEntry>, counter: ReferenceCounter): Json = Json {
|
||||
encodeDefaults = true
|
||||
ignoreUnknownKeys = true
|
||||
classDiscriminator = "_typename"
|
||||
serializersModule = SerializersModule {
|
||||
serializersModule = unrefSerializersModule(refCache, counter)
|
||||
}
|
||||
|
||||
|
||||
fun decode(sourceDeserializer: KSerializer<out TObject>, source: JsonElement): TObject {
|
||||
val counter = ReferenceCounter()
|
||||
val refCache = ArrayList<RefEntry>()
|
||||
|
||||
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().unref(refCache) }
|
||||
shapes(refCache)
|
||||
default { TGeoBBox.serializer() }
|
||||
shapes()
|
||||
}
|
||||
|
||||
polymorphic(TGeoMatrix::class) {
|
||||
matrices(refCache)
|
||||
matrices()
|
||||
}
|
||||
|
||||
polymorphic(TGeoBoolNode::class) {
|
||||
boolNodes()
|
||||
}
|
||||
|
||||
polymorphic(TObject::class) {
|
||||
shapes(refCache)
|
||||
matrices(refCache)
|
||||
subclass(TObjArray.serializer())
|
||||
|
||||
subclass(TGeoMaterial.serializer().unref(refCache))
|
||||
subclass(TGeoMixture.serializer().unref(refCache))
|
||||
shapes()
|
||||
matrices()
|
||||
boolNodes()
|
||||
|
||||
subclass(TGeoMedium.serializer().unref(refCache))
|
||||
subclass(TGeoMaterial.serializer())
|
||||
subclass(TGeoMixture.serializer())
|
||||
|
||||
subclass(TGeoNode.serializer().unref(refCache))
|
||||
subclass(TGeoNodeMatrix.serializer().unref(refCache))
|
||||
subclass(TGeoVolume.serializer().unref(refCache))
|
||||
subclass(TGeoVolumeAssembly.serializer().unref(refCache))
|
||||
subclass(TGeoMedium.serializer())
|
||||
|
||||
subclass(TGeoNode.serializer())
|
||||
subclass(TGeoNodeMatrix.serializer())
|
||||
subclass(TGeoVolume.serializer())
|
||||
subclass(TGeoVolumeAssembly.serializer())
|
||||
}
|
||||
polymorphic(TGeoNode::class, TGeoNode.serializer().unref(refCache)) {
|
||||
subclass(TGeoNodeMatrix.serializer().unref(refCache))
|
||||
|
||||
polymorphic(TGeoNode::class, TGeoNode.serializer()) {
|
||||
subclass(TGeoNodeMatrix.serializer())
|
||||
}
|
||||
polymorphic(TGeoVolume::class, TGeoVolume.serializer().unref(refCache)) {
|
||||
subclass(TGeoVolumeAssembly.serializer().unref(refCache))
|
||||
|
||||
polymorphic(TGeoVolume::class, TGeoVolume.serializer()) {
|
||||
subclass(TGeoVolumeAssembly.serializer())
|
||||
}
|
||||
}
|
||||
|
||||
val json = Json {
|
||||
encodeDefaults = true
|
||||
ignoreUnknownKeys = true
|
||||
classDiscriminator = "_typename"
|
||||
serializersModule = this@RootDecoder.serializersModule
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user