Jetpack ComposeのSlotTableがちょっと読めるようになるメモ

普通にComposeをやる場合は絶対に知らなくていい情報です :warning: 
SlotTableはJetpack Composeのデータ構造のコアとなる部分である認識です。

普通にやるとAndroidのテーマとか色々設定されちゃうので、自作したAppilerなどで最低限のComposeのコードのみの場合で実験してそのデータなどを載せています。

https://github.com/takahirom/draw-android-view-by-jetpack-compose/blob/simple/src/main/kotlin/Main.kt#L63

```kotlin
@Composable
private fun Node() {
    ComposeNode<Node, TextApplier>(
        factory = {
            Node(mutableListOf())
        },
        update = {
        },
    )
}
```

## SlotTable.asString()の結果

```
androidx.compose.runtime.SlotTable@9bbea42
Group(0) key=100, nodes=1, size=7, slots=[0: {}]
 Group(1) key=1000, nodes=1, size=6
  Group(2) key=200, nodes=1, size=5 objectKey=OpaqueKey(key=provider)
   Group(3) key=-985533221, nodes=1, size=4, slots=[2: androidx.compose.runtime.RecomposeScopeImpl@76f0a53, androidx.compose.runtime.internal.ComposableLambdaImpl@e9edf90]
    Group(4) key=-1465440517, nodes=1, size=3, slots=[4: androidx.compose.runtime.RecomposeScopeImpl@b234089]
     Group(5) key=-2103251557, nodes=1, size=2 aux=C(ComposeNode):Composables.kt#9igjgp
      Group(6) key=125, nodes=0, size=1 node=Node(children=[])
```


## SlotTableの構成要素


* groups :IntArray

ここにほとんどすべての情報が入っていそう。ただIntArrayなので、インスタンスの情報についてはslotsが持っているみたい。 
arrayの5個区切りで一つのGroupになっていて、layoutが決まっている。

An array to store group information that is stored as groups of Group_Fields_Size elements of the array. The groups array can be thought of as an array of an inline struct.

private const val Group_Fields_Size = 5

```
// Group layout
//  0             | 1             | 2             | 3             | 4             |
//  Key           | Group info    | Parent anchor | Size          | Data anchor   |
```

データ例

```
0 = 100 // key
1 = 1 // Group info
2 = -1 // Parent anchor
3 = 7 // Size
4 = 0 // Data anchor
5 = 1000 // key
6 = 1 // Group info
7 = 0 // Parent anchor
8 = 6 // Size
9 = 1 // Data anchor
10 = 200  // key
11 = 536870913 // *** Group info ***
12 = 1 // Parent anchor
13 = 5 // Size
14 = 1 // ***Data anchor***
15 = -985533221
16 = 1
17 = 2
18 = 4
19 = 2
20 = -1465440517
21 = 1
22 = 3
23 = 3
24 = 4
25 = -2103251557
26 = 268435457
27 = 4
28 = 2
29 = 5
30 = 125
31 = 1073741824
32 = 5
33 = 1
34 = 6
35 = 0
36 = 0
```

* Group info

groupsの中に入っているgroup infoの情報。
これもフォーマットが決まっている。

```
// Group info is laid out as follows,
// 31 30 29 28_27 26 25 24_23 22 21 20_19 18 17 16__15 14 13 12_11 10 09 08_07 06 05 04_03 02 01 00
// 0  n  ks ds r |                                node count                                       |
// where n is set when the group represents a node
// where ks is whether the group has a object key slot
// where ds is whether the group has a group data slot
// where r is always 0 (future use)

// Parent anchor is a group anchor to the parent, as the group gap is moved this value is updated to
// refer to the parent.

// Slot count is the total number of group slots, including itself, occupied by the group.

// Data anchor is an anchor to the group data. The value is positive if it is before the data gap
// and it is negative if it is after the data gap. As gaps are moved, these values are updated.

// Masks and flags
private const val NodeBit_Mask = 0b0100_0000_0000_0000__0000_0000_0000_0000
private const val ObjectKey_Mask = 0b0010_0000_0000_0000__0000_0000_0000_0000
private const val ObjectKey_Shift = 29
private const val Aux_Mask = 0b0001_0000_0000_0000__0000_0000_0000_0000
private const val Aux_Shift = 28
private const val Slots_Shift = Aux_Shift
private const val NodeCount_Mask = 0b0000_0111_1111_1111__1111_1111_1111_1111
```

* slots

ここに実際のデータが入ってるみたい。recomposeするときに使うRecomposeScopeImplも入っているみたい。

An array that stores the slots for a group. The slot elements for a group start at the offset returned by dataAnchor of groups and continue to the next group's slots or to slotsSize for the last group. When in a writer the dataAnchor is an anchor instead of an index as slots might contain a gap.


データ例

```
0 = {PersistentHashMap@19987}  size = 0
1 = {OpaqueKey@20060} "OpaqueKey(key=provider)"
2 = {RecomposeScopeImpl@20000} 
3 = {ComposableLambdaImpl@20009} 
4 = {RecomposeScopeImpl@19971} 
5 = "C(ComposeNode):Composables.kt#9igjgp"
6 = {Node@20062} "Node(children=[])"
```



## 少し解読してみる


例:

groupsの情報の3番目の要素

```
10 = 200  // key
11 = 536870913 // *** Group info ***
12 = 1 // Parent anchor
13 = 5 // Size
14 = 1 // Data anchor
```

Group infoを2進数に

```
>>> 536870913.toString(2)
res1: kotlin.String = 10_0000_0000_0000_0000_0000_0000_0001
```

private const val ObjectKey_Mask = 0b0010_0000_0000_0000__0000_0000_0000_0000
ObjectKey_Maskがヒット。


Data Ankerは1になっているのでslotの1を見に行く

```
14 = 1 // Data anchor
```

```
1 = {OpaqueKey@20060} "OpaqueKey(key=provider)"
```


asString()での結果にも入っている。

```
  Group(2) key=200, nodes=1, size=5 objectKey=OpaqueKey(key=provider)
```