Optimize Name hashCode

This commit is contained in:
Alexander Nozik 2022-08-23 10:55:00 +03:00
parent 233639f0b6
commit 0cc4dc0db7
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
5 changed files with 48 additions and 9 deletions

View File

@ -9,6 +9,7 @@
- More fine-grained types in Action builders.
### Changed
- Meta `get` method allows nullable receiver
- `withDefault` functions do not add new keys to meta children and are consistent.
- `dataforge.meta.values` package is merged into `dataforge.meta` for better star imports
- Kotlin 1.7.20

View File

@ -5,6 +5,7 @@ import kotlinx.serialization.json.Json
import space.kscience.dataforge.misc.Type
import space.kscience.dataforge.misc.unsafeCast
import space.kscience.dataforge.names.*
import kotlin.jvm.JvmName
/**
@ -94,6 +95,10 @@ public interface Meta : MetaRepr, MetaProvider {
public val Meta.isLeaf: Boolean get() = items.isEmpty()
public operator fun Meta?.get(token: NameToken): Meta? = this?.items?.get(token)
@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN)
@JvmName("getNonNullable")
public operator fun Meta.get(token: NameToken): Meta? = items[token]
/**
@ -103,11 +108,19 @@ public operator fun Meta.get(token: NameToken): Meta? = items[token]
*/
public operator fun Meta?.get(name: Name): Meta? = this?.getMeta(name)
@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN)
@JvmName("getNonNullable")
public operator fun Meta.get(name: Name): Meta? = getMeta(name)
/**
* Parse [Name] from [key] using full name notation and pass it to [Meta.get]
*/
public operator fun Meta?.get(key: String): Meta? = this?.get(key.parseAsName(true))
@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN)
@JvmName("getNonNullable")
public operator fun Meta.get(key: String): Meta? = get(key.parseAsName(true))
/**
* Get all items matching given name. The index of the last element, if present is used as a [Regex],
* against which indexes of elements are matched.
@ -162,7 +175,7 @@ public inline val <M : TypedMeta<M>> TypedMeta<M>.self: M get() = unsafeCast()
//public typealias Meta = TypedMeta<*>
public operator fun <M : TypedMeta<M>> TypedMeta<M>.get(token: NameToken): M? = items[token]
public operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(token: NameToken): M? = this?.items?.get(token)
/**
* Perform recursive item search using given [name]. Each [NameToken] is treated as a name in [TypedMeta.items] of a parent node.
@ -175,11 +188,19 @@ public tailrec operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(name: Name): M?
else -> get(name.firstOrNull()!!)?.get(name.cutFirst())
}
@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN)
@JvmName("getNonNullable")
public operator fun <M : TypedMeta<M>> TypedMeta<M>.get(name: Name): M? = get(name)
/**
* Parse [Name] from [key] using full name notation and pass it to [TypedMeta.get]
*/
public operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(key: String): M? = this[key.parseAsName(true)]
@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN)
@JvmName("getNonNullable")
public operator fun <M : TypedMeta<M>> TypedMeta<M>.get(key: String): M? = get(key)
/**
* Get a sequence of [Name]-[Value] pairs using top-down traversal of the tree

View File

@ -24,13 +24,13 @@ public class Name(public val tokens: List<NameToken>) {
}
}
override fun hashCode(): Int {
return if (tokens.size == 1) {
private val cachedHashCode = if (tokens.size == 1) {
tokens.first().hashCode()
} else {
tokens.hashCode()
}
}
override fun hashCode(): Int = cachedHashCode
public companion object {
public const val NAME_SEPARATOR: String = "."

View File

@ -9,7 +9,7 @@ import space.kscience.dataforge.misc.DFExperimental
* A name token could have appendix in square brackets called *index*
*/
@Serializable(NameTokenSerializer::class)
public data class NameToken(val body: String, val index: String? = null) {
public class NameToken(public val body: String, public val index: String? = null) {
init {
if (body.isEmpty()) error("Syntax error: Name token body is empty")
@ -33,6 +33,7 @@ public data class NameToken(val body: String, val index: String? = null) {
bodyEscaped
}
/**
* Return unescaped version of the [NameToken]. Should be used only for output because it is not possible to correctly
* parse it back.
@ -43,6 +44,22 @@ public data class NameToken(val body: String, val index: String? = null) {
body
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as NameToken
if (body != other.body) return false
if (index != other.index) return false
return true
}
private val cachedHashCode = body.hashCode() * 31 + (index?.hashCode() ?: 0)
override fun hashCode(): Int = cachedHashCode
public companion object {
private val escapedChars = listOf('\\', '.', '[', ']')

View File

@ -33,7 +33,7 @@ public fun Meta.toDynamic(): dynamic {
public class DynamicMeta(internal val obj: dynamic) : TypedMeta<DynamicMeta> {
private fun keys(): Array<String> = js("Object").keys(obj) as Array<String>
private fun isArray(@Suppress("UNUSED_PARAMETER") obj: dynamic): Boolean =
private fun isArray(obj: dynamic): Boolean =
js("Array").isArray(obj) as Boolean
private fun isPrimitive(obj: dynamic): Boolean =