OSDN Git Service

515e1c7860bb6f99c4109c87985dda2d12e77a57
[pf3gnuchains/gcc-fork.git] / libgo / go / exp / norm / triegen.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Trie table generator.
6 // Used by make*tables tools to generate a go file with trie data structures
7 // for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte
8 // sequence are used to lookup offsets in the index table to be used for the
9 // next byte. The last byte is used to index into a table with 16-bit values.
10
11 package main
12
13 import (
14         "fmt"
15         "hash/crc32"
16         "log"
17         "utf8"
18 )
19
20 const blockSize = 64
21 const maxSparseEntries = 16
22
23 // Intermediate trie structure
24 type trieNode struct {
25         table [256]*trieNode
26         value int
27         b     byte
28         leaf  bool
29 }
30
31 func newNode() *trieNode {
32         return new(trieNode)
33 }
34
35 func (n trieNode) String() string {
36         s := fmt.Sprint("trieNode{table: { non-nil at index: ")
37         for i, v := range n.table {
38                 if v != nil {
39                         s += fmt.Sprintf("%d, ", i)
40                 }
41         }
42         s += fmt.Sprintf("}, value:%#x, b:%#x leaf:%v}", n.value, n.b, n.leaf)
43         return s
44 }
45
46 func (n trieNode) isInternal() bool {
47         internal := true
48         for i := 0; i < 256; i++ {
49                 if nn := n.table[i]; nn != nil {
50                         if !internal && !nn.leaf {
51                                 log.Fatalf("triegen: isInternal: node contains both leaf and non-leaf children (%v)", n)
52                         }
53                         internal = internal && !nn.leaf
54                 }
55         }
56         return internal
57 }
58
59 func (n trieNode) mostFrequentStride() int {
60         counts := make(map[int]int)
61         v := 0
62         for _, t := range n.table[0x80 : 0x80+blockSize] {
63                 if t != nil {
64                         if stride := t.value - v; v != 0 && stride >= 0 {
65                                 counts[stride]++
66                         }
67                         v = t.value
68                 }
69         }
70         var maxs, maxc int
71         for stride, cnt := range counts {
72                 if cnt > maxc {
73                         maxs, maxc = stride, cnt
74                 }
75         }
76         return maxs
77 }
78
79 func (n trieNode) countSparseEntries() int {
80         stride := n.mostFrequentStride()
81         var count, v int
82         for _, t := range n.table[0x80 : 0x80+blockSize] {
83                 tv := 0
84                 if t != nil {
85                         tv = t.value
86                 }
87                 if tv-v != stride {
88                         if tv != 0 {
89                                 count++
90                         }
91                 }
92                 v = tv
93         }
94         return count
95 }
96
97 func (n *trieNode) insert(rune int, value uint16) {
98         var p [utf8.UTFMax]byte
99         sz := utf8.EncodeRune(p[:], rune)
100
101         for i := 0; i < sz; i++ {
102                 if n.leaf {
103                         log.Fatalf("triegen: insert: node (%#v) should not be a leaf", n)
104                 }
105                 nn := n.table[p[i]]
106                 if nn == nil {
107                         nn = newNode()
108                         nn.b = p[i]
109                         n.table[p[i]] = nn
110                 }
111                 n = nn
112         }
113         n.value = int(value)
114         n.leaf = true
115 }
116
117 type nodeIndex struct {
118         lookupBlocks []*trieNode
119         valueBlocks  []*trieNode
120         sparseBlocks []*trieNode
121         sparseOffset []uint16
122         sparseCount  int
123
124         lookupBlockIdx map[uint32]int
125         valueBlockIdx  map[uint32]int
126 }
127
128 func newIndex() *nodeIndex {
129         index := &nodeIndex{}
130         index.lookupBlocks = make([]*trieNode, 0)
131         index.valueBlocks = make([]*trieNode, 0)
132         index.sparseBlocks = make([]*trieNode, 0)
133         index.sparseOffset = make([]uint16, 1)
134         index.lookupBlockIdx = make(map[uint32]int)
135         index.valueBlockIdx = make(map[uint32]int)
136         return index
137 }
138
139 func computeOffsets(index *nodeIndex, n *trieNode) int {
140         if n.leaf {
141                 return n.value
142         }
143         hasher := crc32.New(crc32.MakeTable(crc32.IEEE))
144         // We only index continuation bytes.
145         for i := 0; i < blockSize; i++ {
146                 v := 0
147                 if nn := n.table[0x80+i]; nn != nil {
148                         v = computeOffsets(index, nn)
149                 }
150                 hasher.Write([]byte{uint8(v >> 8), uint8(v)})
151         }
152         h := hasher.Sum32()
153         if n.isInternal() {
154                 v, ok := index.lookupBlockIdx[h]
155                 if !ok {
156                         v = len(index.lookupBlocks)
157                         index.lookupBlocks = append(index.lookupBlocks, n)
158                         index.lookupBlockIdx[h] = v
159                 }
160                 n.value = v
161         } else {
162                 v, ok := index.valueBlockIdx[h]
163                 if !ok {
164                         if c := n.countSparseEntries(); c > maxSparseEntries {
165                                 v = len(index.valueBlocks)
166                                 index.valueBlocks = append(index.valueBlocks, n)
167                                 index.valueBlockIdx[h] = v
168                         } else {
169                                 v = -len(index.sparseOffset)
170                                 index.sparseBlocks = append(index.sparseBlocks, n)
171                                 index.sparseOffset = append(index.sparseOffset, uint16(index.sparseCount))
172                                 index.sparseCount += c + 1
173                                 index.valueBlockIdx[h] = v
174                         }
175                 }
176                 n.value = v
177         }
178         return n.value
179 }
180
181 func printValueBlock(nr int, n *trieNode, offset int) {
182         boff := nr * blockSize
183         fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
184         var printnewline bool
185         for i := 0; i < blockSize; i++ {
186                 if i%6 == 0 {
187                         printnewline = true
188                 }
189                 v := 0
190                 if nn := n.table[i+offset]; nn != nil {
191                         v = nn.value
192                 }
193                 if v != 0 {
194                         if printnewline {
195                                 fmt.Printf("\n")
196                                 printnewline = false
197                         }
198                         fmt.Printf("%#04x:%#04x, ", boff+i, v)
199                 }
200         }
201 }
202
203 func printSparseBlock(nr int, n *trieNode) {
204         boff := -n.value
205         fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
206         v := 0
207         //stride := f(n)
208         stride := n.mostFrequentStride()
209         c := n.countSparseEntries()
210         fmt.Printf("\n{value:%#04x,lo:%#02x},", stride, uint8(c))
211         for i, nn := range n.table[0x80 : 0x80+blockSize] {
212                 nv := 0
213                 if nn != nil {
214                         nv = nn.value
215                 }
216                 if nv-v != stride {
217                         if v != 0 {
218                                 fmt.Printf(",hi:%#02x},", 0x80+i-1)
219                         }
220                         if nv != 0 {
221                                 fmt.Printf("\n{value:%#04x,lo:%#02x", nv, nn.b)
222                         }
223                 }
224                 v = nv
225         }
226         if v != 0 {
227                 fmt.Printf(",hi:%#02x},", 0x80+blockSize-1)
228         }
229 }
230
231 func printLookupBlock(nr int, n *trieNode, offset, cutoff int) {
232         boff := nr * blockSize
233         fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
234         var printnewline bool
235         for i := 0; i < blockSize; i++ {
236                 if i%8 == 0 {
237                         printnewline = true
238                 }
239                 v := 0
240                 if nn := n.table[i+offset]; nn != nil {
241                         v = nn.value
242                 }
243                 if v != 0 {
244                         if v < 0 {
245                                 v = -v - 1 + cutoff
246                         }
247                         if printnewline {
248                                 fmt.Printf("\n")
249                                 printnewline = false
250                         }
251                         fmt.Printf("%#03x:%#02x, ", boff+i, v)
252                 }
253         }
254 }
255
256 // printTables returns the size in bytes of the generated tables.
257 func (t *trieNode) printTables(name string) int {
258         index := newIndex()
259         // Values for 7-bit ASCII are stored in first two block, followed by nil block.
260         index.valueBlocks = append(index.valueBlocks, nil, nil, nil)
261         // First byte of multi-byte UTF-8 codepoints are indexed in 4th block.
262         index.lookupBlocks = append(index.lookupBlocks, nil, nil, nil, nil)
263         // Index starter bytes of multi-byte UTF-8.
264         for i := 0xC0; i < 0x100; i++ {
265                 if t.table[i] != nil {
266                         computeOffsets(index, t.table[i])
267                 }
268         }
269
270         nv := len(index.valueBlocks) * blockSize
271         fmt.Printf("// %sValues: %d entries, %d bytes\n", name, nv, nv*2)
272         fmt.Printf("// Block 2 is the null block.\n")
273         fmt.Printf("var %sValues = [%d]uint16 {", name, nv)
274         printValueBlock(0, t, 0)
275         printValueBlock(1, t, 64)
276         printValueBlock(2, newNode(), 0)
277         for i := 3; i < len(index.valueBlocks); i++ {
278                 printValueBlock(i, index.valueBlocks[i], 0x80)
279         }
280         fmt.Print("\n}\n\n")
281
282         ls := len(index.sparseBlocks)
283         fmt.Printf("// %sSparseOffset: %d entries, %d bytes\n", name, ls, ls*2)
284         fmt.Printf("var %sSparseOffset = %#v\n\n", name, index.sparseOffset[1:])
285
286         ns := index.sparseCount
287         fmt.Printf("// %sSparseValues: %d entries, %d bytes\n", name, ns, ns*4)
288         fmt.Printf("var %sSparseValues = [%d]valueRange {", name, ns)
289         for i, n := range index.sparseBlocks {
290                 printSparseBlock(i, n)
291         }
292         fmt.Print("\n}\n\n")
293
294         cutoff := len(index.valueBlocks)
295         ni := len(index.lookupBlocks) * blockSize
296         fmt.Printf("// %sLookup: %d bytes\n", name, ni)
297         fmt.Printf("// Block 0 is the null block.\n")
298         fmt.Printf("var %sLookup = [%d]uint8 {", name, ni)
299         printLookupBlock(0, newNode(), 0, cutoff)
300         printLookupBlock(1, newNode(), 0, cutoff)
301         printLookupBlock(2, newNode(), 0, cutoff)
302         printLookupBlock(3, t, 0xC0, cutoff)
303         for i := 4; i < len(index.lookupBlocks); i++ {
304                 printLookupBlock(i, index.lookupBlocks[i], 0x80, cutoff)
305         }
306         fmt.Print("\n}\n\n")
307         fmt.Printf("var %sTrie = trie{ %sLookup[:], %sValues[:], %sSparseValues[:], %sSparseOffset[:], %d}\n\n",
308                 name, name, name, name, name, cutoff)
309         return nv*2 + ns*4 + ni + ls*2
310 }