普通にComposeをやる場合は絶対に知らなくていい情報です
SlotTableはJetpack Composeのデータ構造のコアとなる部分である認識です。
普通にやるとAndroidのテーマとか色々設定されちゃうので、自作したAppilerなどで最低限のComposeのコードのみの場合で実験してそのデータなどを載せています。
@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)