summaryrefslogtreecommitdiff
path: root/Tools/lua-snapshot/snapshot_utils.lua
blob: a041ba3dc3b1ecfe96f38612180a4648e9f4ba7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
local function trim(s)
    return (s:gsub("^%s*(.-)%s*$", "%1"))
end

local function cleanup_key_value(input)
    local ret = {}
    for k, v in pairs(input) do
        local key = tostring(k)
        local clean_key = key:gmatch("userdata: 0x(%w+)")()
        local val_type
        if v:find("^table") then
            val_type = "table"
        elseif v:find("^func:") then
            val_type = "func"
        elseif v:find("^thread:") then
            val_type = "thread"
        else
            val_type = "userdata"
        end
        local parent = v:match("0x(%w+) :")
        local _, finish = v:find("0x(%w+) : ")
        local extra = v:sub(finish + 1, #v)
        local val_key = extra:match("(%w+) :")
        local trim_extra = trim(extra)
        if not val_key then
            val_key = trim_extra
        end
        ret[clean_key] = {
            val_type = val_type,
            parent = parent,
            extra = trim_extra,
            key = val_key,
        }
    end
    return ret
end

local function reduce(input_diff)
    local a_set = {}
    local b_set = {}
    local step = 0
    -- 先收入叶节点
    for self_addr, info in pairs(input_diff) do
        local flag = true
        for _, node in pairs(input_diff) do
            if node.parent == self_addr then
                flag = false
                break
            end
        end
        if flag then
            a_set[self_addr] = info
        end
    end
    step = step + 1
    local MAX_DEPTH = 32
    local dirty
    while step < MAX_DEPTH do
        dirty = false
        -- 遍历叶节点,将parent拉进来
        for self_addr, info in pairs(a_set) do
            local key = info.key
            local parent = info.parent
            local parent_node = input_diff[parent]
            if parent_node then
                if not b_set[parent] then
                    b_set[parent] = parent_node
                end
                parent_node[key] = info
                step = step + 1
                dirty = true
            else
                b_set[self_addr] = info
            end
            a_set[self_addr] = nil
        end
        -- 遍历节点,将祖父节点拉进来
        for self_addr, info in pairs(b_set) do
            local key = info.key
            local parent = info.parent
            local parent_node = input_diff[parent]
            if parent_node then
                if not a_set[parent] then
                    a_set[parent] = parent_node
                end
                parent_node[key] = info
                step = step + 1
                dirty = true
            else
                a_set[self_addr] = info
            end
            b_set[self_addr] = nil
        end
        if not dirty then
            break
        end
    end
    return a_set
end

local unwanted_key = {
    --extra = 1,
    --key = 1,
    parent = 1,
}
local function cleanup_forest(input)
    local cache = {[input] = "."}
    local function _clean(forest)
        if cache[forest] then
            return
        end
        for k, v in pairs(forest) do
            if unwanted_key[k] then
                forest[k] = nil
            else
                if type(v) == "table" then
                    cleanup_forest(v)
                end
             end
         end
	end
    return _clean(input)
end

local M = {}
function M.construct_indentation(input_diff)
    local clean_diff = cleanup_key_value(input_diff)
    local forest = reduce(clean_diff)
    cleanup_forest(forest)
    return forest
end

return M