Remove node Id from descriptor
Summary: It was always the system hash code and in many places it was inconvient to get the descriptor to just end up calling the same function Reviewed By: lblasa Differential Revision: D39700215 fbshipit-source-id: b1439d56cd8f39ba8735f933662ad79b87ffbdbe
This commit is contained in:
committed by
Facebook GitHub Bot
parent
32b7a5589f
commit
9bc2f6fec5
@@ -17,7 +17,6 @@ import com.facebook.litho.DebugComponent
|
|||||||
import com.facebook.litho.LithoView
|
import com.facebook.litho.LithoView
|
||||||
|
|
||||||
object LithoViewDescriptor : NodeDescriptor<LithoView> {
|
object LithoViewDescriptor : NodeDescriptor<LithoView> {
|
||||||
override fun getId(node: LithoView): String = System.identityHashCode(node).toString()
|
|
||||||
|
|
||||||
override fun getName(node: LithoView): String = "LithoView"
|
override fun getName(node: LithoView): String = "LithoView"
|
||||||
|
|
||||||
@@ -45,7 +44,6 @@ const val LithoTag = "Litho"
|
|||||||
class MountedObject(val obj: Any, val descriptor: NodeDescriptor<Any>)
|
class MountedObject(val obj: Any, val descriptor: NodeDescriptor<Any>)
|
||||||
|
|
||||||
object MountedObjectDescriptor : NodeDescriptor<MountedObject> {
|
object MountedObjectDescriptor : NodeDescriptor<MountedObject> {
|
||||||
override fun getId(node: MountedObject): String = node.descriptor.getId(node.obj)
|
|
||||||
|
|
||||||
override fun getBounds(node: MountedObject): Bounds? {
|
override fun getBounds(node: MountedObject): Bounds? {
|
||||||
val bounds = node.descriptor.getBounds(node.obj)
|
val bounds = node.descriptor.getBounds(node.obj)
|
||||||
@@ -72,7 +70,6 @@ object MountedObjectDescriptor : NodeDescriptor<MountedObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DebugComponentDescriptor(val register: DescriptorRegister) : NodeDescriptor<DebugComponent> {
|
class DebugComponentDescriptor(val register: DescriptorRegister) : NodeDescriptor<DebugComponent> {
|
||||||
override fun getId(node: DebugComponent): String = System.identityHashCode(node).toString()
|
|
||||||
|
|
||||||
override fun getName(node: DebugComponent): String {
|
override fun getName(node: DebugComponent): String {
|
||||||
return node.component.simpleName
|
return node.component.simpleName
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ package com.facebook.flipper.plugins.uidebugger.litho
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.nodeId
|
||||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserver
|
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserver
|
||||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverBuilder
|
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverBuilder
|
||||||
import com.facebook.litho.LithoView
|
import com.facebook.litho.LithoView
|
||||||
@@ -22,6 +23,8 @@ class LithoViewTreeObserver(val context: Context) : TreeObserver<LithoView>() {
|
|||||||
|
|
||||||
override fun subscribe(node: Any) {
|
override fun subscribe(node: Any) {
|
||||||
|
|
||||||
|
Log.i(LogTag, "Subscribing to litho view ${node.nodeId()}")
|
||||||
|
|
||||||
nodeRef = node as LithoView
|
nodeRef = node as LithoView
|
||||||
|
|
||||||
val listener: (view: LithoView) -> Unit = { traverseAndSend(context, node) }
|
val listener: (view: LithoView) -> Unit = { traverseAndSend(context, node) }
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.facebook.flipper.core.FlipperConnection
|
|||||||
import com.facebook.flipper.core.FlipperPlugin
|
import com.facebook.flipper.core.FlipperPlugin
|
||||||
import com.facebook.flipper.plugins.uidebugger.core.*
|
import com.facebook.flipper.plugins.uidebugger.core.*
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.nodeId
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.InitEvent
|
import com.facebook.flipper.plugins.uidebugger.model.InitEvent
|
||||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
|
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
|
||||||
import com.facebook.flipper.plugins.uidebugger.scheduler.Scheduler
|
import com.facebook.flipper.plugins.uidebugger.scheduler.Scheduler
|
||||||
@@ -54,8 +55,7 @@ class UIDebuggerFlipperPlugin(
|
|||||||
|
|
||||||
connection.send(
|
connection.send(
|
||||||
InitEvent.name,
|
InitEvent.name,
|
||||||
Json.encodeToString(
|
Json.encodeToString(InitEvent.serializer(), InitEvent(context.applicationRef.nodeId())))
|
||||||
InitEvent.serializer(), InitEvent(rootDescriptor.getId(context.applicationRef))))
|
|
||||||
|
|
||||||
context.treeObserverManager.start()
|
context.treeObserverManager.start()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ import com.facebook.flipper.plugins.uidebugger.core.FragmentTracker
|
|||||||
|
|
||||||
object ActivityDescriptor : ChainedDescriptor<Activity>() {
|
object ActivityDescriptor : ChainedDescriptor<Activity>() {
|
||||||
|
|
||||||
override fun onGetId(node: Activity): String {
|
|
||||||
return System.identityHashCode(node).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetName(node: Activity): String {
|
override fun onGetName(node: Activity): String {
|
||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,6 @@ object ApplicationRefDescriptor : ChainedDescriptor<ApplicationRef>() {
|
|||||||
return if (node.activitiesStack.isNotEmpty()) node.activitiesStack.last() else null
|
return if (node.activitiesStack.isNotEmpty()) node.activitiesStack.last() else null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetId(node: ApplicationRef): String {
|
|
||||||
return node.application.packageName
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetBounds(node: ApplicationRef): Bounds {
|
override fun onGetBounds(node: ApplicationRef): Bounds {
|
||||||
val displayMetrics = Resources.getSystem().getDisplayMetrics()
|
val displayMetrics = Resources.getSystem().getDisplayMetrics()
|
||||||
return Bounds(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels)
|
return Bounds(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels)
|
||||||
|
|||||||
@@ -12,10 +12,6 @@ import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
|||||||
|
|
||||||
object ButtonDescriptor : ChainedDescriptor<Button>() {
|
object ButtonDescriptor : ChainedDescriptor<Button>() {
|
||||||
|
|
||||||
override fun onGetId(node: Button): String {
|
|
||||||
return System.identityHashCode(node).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetName(node: Button): String {
|
override fun onGetName(node: Button): String {
|
||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,16 +39,6 @@ abstract class ChainedDescriptor<T> : NodeDescriptor<T> {
|
|||||||
return onGetActiveChild(node) ?: mSuper?.getActiveChild(node)
|
return onGetActiveChild(node) ?: mSuper?.getActiveChild(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A globally unique ID used to identify a node in a hierarchy. If your node does not have a
|
|
||||||
* globally unique ID it is fine to rely on [System.identityHashCode].
|
|
||||||
*/
|
|
||||||
final override fun getId(node: T): String {
|
|
||||||
return onGetId(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun onGetId(node: T): String
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name used to identify this node in the inspector. Does not need to be unique. A good
|
* The name used to identify this node in the inspector. Does not need to be unique. A good
|
||||||
* default is to use the class name of the node.
|
* default is to use the class name of the node.
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
|||||||
|
|
||||||
object FragmentFrameworkDescriptor : ChainedDescriptor<android.app.Fragment>() {
|
object FragmentFrameworkDescriptor : ChainedDescriptor<android.app.Fragment>() {
|
||||||
|
|
||||||
override fun onGetId(node: android.app.Fragment): String {
|
|
||||||
return System.identityHashCode(node).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetName(node: android.app.Fragment): String {
|
override fun onGetName(node: android.app.Fragment): String {
|
||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
|||||||
|
|
||||||
object FragmentSupportDescriptor : ChainedDescriptor<androidx.fragment.app.Fragment>() {
|
object FragmentSupportDescriptor : ChainedDescriptor<androidx.fragment.app.Fragment>() {
|
||||||
|
|
||||||
override fun onGetId(node: androidx.fragment.app.Fragment): String {
|
|
||||||
return System.identityHashCode(node).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetName(node: androidx.fragment.app.Fragment): String {
|
override fun onGetName(node: androidx.fragment.app.Fragment): String {
|
||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,6 @@ object BaseTags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface NodeDescriptor<T> {
|
interface NodeDescriptor<T> {
|
||||||
/**
|
|
||||||
* A globally unique ID used to identify a node in a hierarchy. If your node does not have a
|
|
||||||
* globally unique ID it is fine to rely on [System.identityHashCode].
|
|
||||||
*/
|
|
||||||
fun getId(node: T): String
|
|
||||||
|
|
||||||
/** Should be w.r.t the direct parent */
|
/** Should be w.r.t the direct parent */
|
||||||
fun getBounds(node: T): Bounds?
|
fun getBounds(node: T): Bounds?
|
||||||
@@ -65,3 +60,9 @@ interface NodeDescriptor<T> {
|
|||||||
*/
|
*/
|
||||||
fun getTags(node: T): Set<String>
|
fun getTags(node: T): Set<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typealias Id = Int
|
||||||
|
|
||||||
|
fun Any.nodeId(): Id {
|
||||||
|
return System.identityHashCode(this)
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ object ObjectDescriptor : NodeDescriptor<Any> {
|
|||||||
|
|
||||||
override fun getActiveChild(node: Any): Any? = null
|
override fun getActiveChild(node: Any): Any? = null
|
||||||
|
|
||||||
override fun getId(node: Any): String {
|
|
||||||
return System.identityHashCode(node).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getName(node: Any): String {
|
override fun getName(node: Any): String {
|
||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,6 @@ import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
|||||||
|
|
||||||
object TextViewDescriptor : ChainedDescriptor<TextView>() {
|
object TextViewDescriptor : ChainedDescriptor<TextView>() {
|
||||||
|
|
||||||
override fun onGetId(node: TextView): String {
|
|
||||||
return System.identityHashCode(node).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetName(node: TextView): String {
|
override fun onGetName(node: TextView): String {
|
||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,6 @@ import java.lang.reflect.Field
|
|||||||
|
|
||||||
object ViewDescriptor : ChainedDescriptor<View>() {
|
object ViewDescriptor : ChainedDescriptor<View>() {
|
||||||
|
|
||||||
override fun onGetId(node: View): String {
|
|
||||||
return Integer.toBinaryString(System.identityHashCode(node))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetName(node: View): String {
|
override fun onGetName(node: View): String {
|
||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,6 @@ import com.facebook.flipper.plugins.uidebugger.core.FragmentTracker
|
|||||||
|
|
||||||
object ViewGroupDescriptor : ChainedDescriptor<ViewGroup>() {
|
object ViewGroupDescriptor : ChainedDescriptor<ViewGroup>() {
|
||||||
|
|
||||||
override fun onGetId(node: ViewGroup): String {
|
|
||||||
return System.identityHashCode(node).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetName(node: ViewGroup): String {
|
override fun onGetName(node: ViewGroup): String {
|
||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import androidx.viewpager.widget.ViewPager
|
|||||||
|
|
||||||
object ViewPagerDescriptor : ChainedDescriptor<ViewPager>() {
|
object ViewPagerDescriptor : ChainedDescriptor<ViewPager>() {
|
||||||
|
|
||||||
override fun onGetId(node: ViewPager): String = System.identityHashCode(node).toString()
|
|
||||||
|
|
||||||
override fun onGetName(node: ViewPager): String = node.javaClass.simpleName
|
override fun onGetName(node: ViewPager): String = node.javaClass.simpleName
|
||||||
|
|
||||||
override fun onGetActiveChild(node: ViewPager): Any? = node.getChildAt(node.currentItem)
|
override fun onGetActiveChild(node: ViewPager): Any? = node.getChildAt(node.currentItem)
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ import android.view.Window
|
|||||||
|
|
||||||
object WindowDescriptor : ChainedDescriptor<Window>() {
|
object WindowDescriptor : ChainedDescriptor<Window>() {
|
||||||
|
|
||||||
override fun onGetId(node: Window): String {
|
|
||||||
return System.identityHashCode(node).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGetName(node: Window): String {
|
override fun onGetName(node: Window): String {
|
||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,10 @@
|
|||||||
|
|
||||||
package com.facebook.flipper.plugins.uidebugger.model
|
package com.facebook.flipper.plugins.uidebugger.model
|
||||||
|
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class InitEvent(val rootId: String) {
|
data class InitEvent(val rootId: Id) {
|
||||||
companion object {
|
companion object {
|
||||||
const val name = "init"
|
const val name = "init"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,16 +8,17 @@
|
|||||||
package com.facebook.flipper.plugins.uidebugger.model
|
package com.facebook.flipper.plugins.uidebugger.model
|
||||||
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class Node(
|
data class Node(
|
||||||
val id: String,
|
val id: Id,
|
||||||
val name: String,
|
val name: String,
|
||||||
val attributes: Map<String, InspectableObject>,
|
val attributes: Map<String, InspectableObject>,
|
||||||
val bounds: Bounds?,
|
val bounds: Bounds?,
|
||||||
val tags: Set<String>,
|
val tags: Set<String>,
|
||||||
val children: List<String>,
|
val children: List<Id>,
|
||||||
val activeChild: String?,
|
val activeChild: Id?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ package com.facebook.flipper.plugins.uidebugger.observers
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.nodeId
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.Node
|
import com.facebook.flipper.plugins.uidebugger.model.Node
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,7 +50,7 @@ class PartialLayoutTraversal(
|
|||||||
|
|
||||||
val children = descriptor.getChildren(node)
|
val children = descriptor.getChildren(node)
|
||||||
|
|
||||||
val childrenIds = mutableListOf<String>()
|
val childrenIds = mutableListOf<Id>()
|
||||||
val activeChild = descriptor.getActiveChild(node)
|
val activeChild = descriptor.getActiveChild(node)
|
||||||
|
|
||||||
for (child in children) {
|
for (child in children) {
|
||||||
@@ -56,17 +58,16 @@ class PartialLayoutTraversal(
|
|||||||
// hash code
|
// hash code
|
||||||
val childDescriptor =
|
val childDescriptor =
|
||||||
descriptorRegister.descriptorForClassUnsafe(child::class.java).asAny()
|
descriptorRegister.descriptorForClassUnsafe(child::class.java).asAny()
|
||||||
childrenIds.add(childDescriptor.getId(child))
|
childrenIds.add(child.nodeId())
|
||||||
// If there is an active child then don't traverse it
|
// If there is an active child then don't traverse it
|
||||||
if (activeChild == null) {
|
if (activeChild == null) {
|
||||||
stack.add(child)
|
stack.add(child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var activeChildId: String? = null
|
var activeChildId: Id? = null
|
||||||
if (activeChild != null) {
|
if (activeChild != null) {
|
||||||
stack.add(activeChild)
|
stack.add(activeChild)
|
||||||
activeChildId =
|
activeChildId = activeChild.nodeId()
|
||||||
descriptorRegister.descriptorForClassUnsafe(activeChild.javaClass).getId(activeChild)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val attributes = descriptor.getData(node)
|
val attributes = descriptor.getData(node)
|
||||||
@@ -75,7 +76,7 @@ class PartialLayoutTraversal(
|
|||||||
|
|
||||||
visited.add(
|
visited.add(
|
||||||
Node(
|
Node(
|
||||||
descriptor.getId(node),
|
node.nodeId(),
|
||||||
descriptor.getName(node),
|
descriptor.getName(node),
|
||||||
attributes,
|
attributes,
|
||||||
bounds,
|
bounds,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ package com.facebook.flipper.plugins.uidebugger.observers
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.nodeId
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Represents a stateful observer that manages some subtree in the UI Hierarchy.
|
* Represents a stateful observer that manages some subtree in the UI Hierarchy.
|
||||||
@@ -44,19 +45,19 @@ abstract class TreeObserver<T> {
|
|||||||
|
|
||||||
// Add any new observers
|
// Add any new observers
|
||||||
for (observerRoot in observerRootsNodes) {
|
for (observerRoot in observerRootsNodes) {
|
||||||
if (!children.containsKey(observerRoot.identityHashCode())) {
|
if (!children.containsKey(observerRoot.nodeId())) {
|
||||||
context.observerFactory.createObserver(observerRoot, context)?.let { childObserver ->
|
context.observerFactory.createObserver(observerRoot, context)?.let { childObserver ->
|
||||||
Log.d(
|
Log.d(
|
||||||
LogTag,
|
LogTag,
|
||||||
"Observer ${this.type} discovered new child of type ${childObserver.type} Node ID ${observerRoot.identityHashCode()}")
|
"Observer ${this.type} discovered new child of type ${childObserver.type} Node ID ${observerRoot.nodeId()}")
|
||||||
childObserver.subscribe(observerRoot)
|
childObserver.subscribe(observerRoot)
|
||||||
children[observerRoot.identityHashCode()] = childObserver
|
children[observerRoot.nodeId()] = childObserver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any old observers
|
// Remove any old observers
|
||||||
val observerRootIds = observerRootsNodes.map { it.identityHashCode() }
|
val observerRootIds = observerRootsNodes.map { it.nodeId() }
|
||||||
for (childKey in children.keys) {
|
for (childKey in children.keys) {
|
||||||
if (!observerRootIds.contains(childKey)) {
|
if (!observerRootIds.contains(childKey)) {
|
||||||
children[childKey]?.let { childObserver ->
|
children[childKey]?.let { childObserver ->
|
||||||
@@ -81,9 +82,3 @@ abstract class TreeObserver<T> {
|
|||||||
children.clear()
|
children.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias HashCode = Int
|
|
||||||
|
|
||||||
fun Any.identityHashCode(): HashCode {
|
|
||||||
return System.identityHashCode(this)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user