интернированые адаптеры

This commit is contained in:
DBotThePony 2023-02-09 19:30:52 +07:00
parent a5668b57e6
commit e01afbefe7
Signed by: DBot
GPG Key ID: DCC23B5715498507
4 changed files with 88 additions and 19 deletions

View File

@ -42,6 +42,8 @@ import ru.dbotthepony.kstarbound.io.*
import ru.dbotthepony.kstarbound.io.json.AABBTypeAdapter import ru.dbotthepony.kstarbound.io.json.AABBTypeAdapter
import ru.dbotthepony.kstarbound.io.json.AABBiTypeAdapter import ru.dbotthepony.kstarbound.io.json.AABBiTypeAdapter
import ru.dbotthepony.kstarbound.io.json.EitherTypeAdapter import ru.dbotthepony.kstarbound.io.json.EitherTypeAdapter
import ru.dbotthepony.kstarbound.io.json.InternedJsonElementAdapter
import ru.dbotthepony.kstarbound.io.json.InternedStringAdapter
import ru.dbotthepony.kstarbound.io.json.Vector2dTypeAdapter import ru.dbotthepony.kstarbound.io.json.Vector2dTypeAdapter
import ru.dbotthepony.kstarbound.io.json.Vector2fTypeAdapter import ru.dbotthepony.kstarbound.io.json.Vector2fTypeAdapter
import ru.dbotthepony.kstarbound.io.json.Vector2iTypeAdapter import ru.dbotthepony.kstarbound.io.json.Vector2iTypeAdapter
@ -105,25 +107,14 @@ class Starbound : ISBFileLocator {
setFieldNamingPolicy(FieldNamingPolicy.IDENTITY) setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
setPrettyPrinting() setPrettyPrinting()
// чтоб строки всегда intern'ились registerTypeAdapter(InternedStringAdapter(stringInterner))
registerTypeAdapter(object : TypeAdapter<String>() { registerTypeAdapter(InternedJsonElementAdapter(stringInterner))
override fun write(out: JsonWriter, value: String?) {
if (value == null)
out.nullValue()
else
out.value(value)
}
override fun read(`in`: JsonReader): String? {
return stringInterner.intern(TypeAdapters.STRING.read(`in`) ?: return null)
}
})
// Обработчик @JsonImplementation // Обработчик @JsonImplementation
registerTypeAdapterFactory(JsonImplementationTypeFactory) registerTypeAdapterFactory(JsonImplementationTypeFactory)
// ImmutableList, ImmutableSet, ImmutableMap // ImmutableList, ImmutableSet, ImmutableMap
registerTypeAdapterFactory(ImmutableCollectionAdapterFactory) registerTypeAdapterFactory(ImmutableCollectionAdapterFactory(stringInterner))
// ArrayList // ArrayList
registerTypeAdapterFactory(ArrayListAdapterFactory) registerTypeAdapterFactory(ArrayListAdapterFactory)

View File

@ -0,0 +1,63 @@
package ru.dbotthepony.kstarbound.io.json
import com.google.common.collect.Interner
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonNull
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import com.google.gson.TypeAdapter
import com.google.gson.internal.LazilyParsedNumber
import com.google.gson.internal.bind.TypeAdapters
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
class InternedJsonElementAdapter(val stringInterner: Interner<String>) : TypeAdapter<JsonElement>() {
private val _true = JsonPrimitive(true)
private val _false = JsonPrimitive(false)
override fun write(out: JsonWriter, value: JsonElement?) {
return TypeAdapters.JSON_ELEMENT.write(out, value)
}
override fun read(`in`: JsonReader): JsonElement? {
return when (val p = `in`.peek()) {
JsonToken.STRING -> JsonPrimitive(stringInterner.intern(`in`.nextString()))
JsonToken.NUMBER -> JsonPrimitive(LazilyParsedNumber(`in`.nextString()))
JsonToken.BOOLEAN -> if (`in`.nextBoolean()) _true else _false
JsonToken.NULL -> JsonNull.INSTANCE
JsonToken.BEGIN_ARRAY -> {
val output = JsonArray()
`in`.beginArray()
while (`in`.hasNext()) { output.add(read(`in`)) }
`in`.endArray()
output
}
JsonToken.BEGIN_OBJECT -> {
val output = JsonObject()
`in`.beginObject()
while (`in`.hasNext()) { output.add(stringInterner.intern(`in`.nextName()), read(`in`)) }
`in`.endObject()
output
}
else -> throw IllegalArgumentException(p.toString())
}
}
}
class InternedStringAdapter(val stringInterner: Interner<String>) : TypeAdapter<String>() {
override fun write(out: JsonWriter, value: String?) {
out.value(value)
}
override fun read(`in`: JsonReader): String? {
if (`in`.peek() == JsonToken.NULL)
return null
if (`in`.peek() == JsonToken.BOOLEAN)
return `in`.nextBoolean().toString()
return stringInterner.intern(`in`.nextString())
}
}

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.kstarbound.io.json.factory
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap import com.google.common.collect.ImmutableMap
import com.google.common.collect.ImmutableSet import com.google.common.collect.ImmutableSet
import com.google.common.collect.Interner
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory import com.google.gson.TypeAdapterFactory
@ -10,7 +11,7 @@ import com.google.gson.internal.`$Gson$Types`
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
@Suppress("unchecked_cast") @Suppress("unchecked_cast")
object ImmutableCollectionAdapterFactory : TypeAdapterFactory { class ImmutableCollectionAdapterFactory(val stringInterner: Interner<String> = Interner { it }) : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? { override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
when (type.rawType) { when (type.rawType) {
ImmutableList::class.java -> { ImmutableList::class.java -> {
@ -27,7 +28,7 @@ object ImmutableCollectionAdapterFactory : TypeAdapterFactory {
val (elementType0, elementType1) = `$Gson$Types`.getMapKeyAndValueTypes(type.type, type.rawType) val (elementType0, elementType1) = `$Gson$Types`.getMapKeyAndValueTypes(type.type, type.rawType)
if (`$Gson$Types`.getRawType(elementType0) == String::class.java) { if (`$Gson$Types`.getRawType(elementType0) == String::class.java) {
return ImmutableMapTypeAdapter(gson.getAdapter(TypeToken.get(elementType1)))as TypeAdapter<T> return ImmutableMapTypeAdapter(stringInterner, gson.getAdapter(TypeToken.get(elementType1))) as TypeAdapter<T>
} }
return ImmutableArrayMapTypeAdapter( return ImmutableArrayMapTypeAdapter(

View File

@ -2,13 +2,14 @@ package ru.dbotthepony.kstarbound.io.json.factory
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap import com.google.common.collect.ImmutableMap
import com.google.common.collect.Interner
import com.google.gson.JsonSyntaxException import com.google.gson.JsonSyntaxException
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
class ImmutableMapTypeAdapter<V>(val elementAdapter: TypeAdapter<V>) : TypeAdapter<ImmutableMap<String, V>>() { class ImmutableMapTypeAdapter<V>(val stringInterner: Interner<String>, val elementAdapter: TypeAdapter<V>) : TypeAdapter<ImmutableMap<String, V>>() {
override fun write(out: JsonWriter, value: ImmutableMap<String, V>?) { override fun write(out: JsonWriter, value: ImmutableMap<String, V>?) {
if (value == null) { if (value == null) {
out.nullValue() out.nullValue()
@ -29,12 +30,25 @@ class ImmutableMapTypeAdapter<V>(val elementAdapter: TypeAdapter<V>) : TypeAdapt
if (reader.peek() == JsonToken.NULL) if (reader.peek() == JsonToken.NULL)
return null return null
if (reader.peek() == JsonToken.BEGIN_ARRAY) {
val builder = ImmutableMap.Builder<String, V>()
while (reader.peek() !== JsonToken.END_ARRAY) {
builder.put(
stringInterner.intern(reader.nextString()),
elementAdapter.read(reader) ?: throw JsonSyntaxException("Nulls are not allowed, near ${reader.path}")
)
}
return builder.build()
}
reader.beginObject() reader.beginObject()
val builder = ImmutableMap.Builder<String, V>() val builder = ImmutableMap.Builder<String, V>()
while (reader.peek() != JsonToken.END_OBJECT) { while (reader.peek() !== JsonToken.END_OBJECT) {
builder.put(reader.nextName(), elementAdapter.read(reader) ?: throw JsonSyntaxException("Nulls are not allowed, near ${reader.path}")) builder.put(stringInterner.intern(reader.nextName()), elementAdapter.read(reader) ?: throw JsonSyntaxException("Nulls are not allowed, near ${reader.path}"))
} }
reader.endObject() reader.endObject()