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