1
2
3
4
5 package ssa
6
7 import (
8 "math/bits"
9 )
10
11
12
13
14
15
16
17 type lcaRange struct {
18
19 blocks []lcaRangeBlock
20
21
22
23
24 rangeMin [][]ID
25 }
26
27 type lcaRangeBlock struct {
28 b *Block
29 parent ID
30 firstChild ID
31 sibling ID
32 pos int32
33 depth int32
34 }
35
36 func makeLCArange(f *Func) *lcaRange {
37 dom := f.Idom()
38
39
40 blocks := make([]lcaRangeBlock, f.NumBlocks())
41 for _, b := range f.Blocks {
42 blocks[b.ID].b = b
43 if dom[b.ID] == nil {
44 continue
45 }
46 parent := dom[b.ID].ID
47 blocks[b.ID].parent = parent
48 blocks[b.ID].sibling = blocks[parent].firstChild
49 blocks[parent].firstChild = b.ID
50 }
51
52
53
54 tour := make([]ID, 0, f.NumBlocks()*2-1)
55 type queueEntry struct {
56 bid ID
57 cid ID
58 }
59 q := []queueEntry{{f.Entry.ID, 0}}
60 for len(q) > 0 {
61 n := len(q) - 1
62 bid := q[n].bid
63 cid := q[n].cid
64 q = q[:n]
65
66
67 blocks[bid].pos = int32(len(tour))
68 tour = append(tour, bid)
69
70
71 if cid == 0 {
72
73 blocks[bid].depth = blocks[blocks[bid].parent].depth + 1
74
75 cid = blocks[bid].firstChild
76 } else {
77
78 cid = blocks[cid].sibling
79 }
80 if cid != 0 {
81 q = append(q, queueEntry{bid, cid}, queueEntry{cid, 0})
82 }
83 }
84
85
86 rangeMin := make([][]ID, 0, bits.Len64(uint64(len(tour))))
87 rangeMin = append(rangeMin, tour)
88 for logS, s := 1, 2; s < len(tour); logS, s = logS+1, s*2 {
89 r := make([]ID, len(tour)-s+1)
90 for i := 0; i < len(tour)-s+1; i++ {
91 bid := rangeMin[logS-1][i]
92 bid2 := rangeMin[logS-1][i+s/2]
93 if blocks[bid2].depth < blocks[bid].depth {
94 bid = bid2
95 }
96 r[i] = bid
97 }
98 rangeMin = append(rangeMin, r)
99 }
100
101 return &lcaRange{blocks: blocks, rangeMin: rangeMin}
102 }
103
104
105 func (lca *lcaRange) find(a, b *Block) *Block {
106 if a == b {
107 return a
108 }
109
110 p1 := lca.blocks[a.ID].pos
111 p2 := lca.blocks[b.ID].pos
112 if p1 > p2 {
113 p1, p2 = p2, p1
114 }
115
116
117
118
119
120 logS := uint(log64(int64(p2 - p1)))
121 bid1 := lca.rangeMin[logS][p1]
122 bid2 := lca.rangeMin[logS][p2-1<<logS+1]
123 if lca.blocks[bid1].depth < lca.blocks[bid2].depth {
124 return lca.blocks[bid1].b
125 }
126 return lca.blocks[bid2].b
127 }
128
View as plain text