blob: 7e373a54c7cd2e4afe05ed5de688743a3d2e548d [file] [log] [blame]
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
import (
"log"
"strings"
"unicode"
"golang.org/x/text/internal/gen"
"golang.org/x/text/internal/ucd"
)
// snippet is a slice of data; data is the concatenation of all of the names.
type snippet struct {
offset int
length int
s string
}
func makeTable0EntryDirect(rOffset, rLength, dOffset, dLength int) uint64 {
if rOffset >= 1<<bitsRuneOffset {
log.Fatalf("makeTable0EntryDirect: rOffset %d is too large", rOffset)
}
if rLength >= 1<<bitsRuneLength {
log.Fatalf("makeTable0EntryDirect: rLength %d is too large", rLength)
}
if dOffset >= 1<<bitsDataOffset {
log.Fatalf("makeTable0EntryDirect: dOffset %d is too large", dOffset)
}
if dLength >= 1<<bitsRuneLength {
log.Fatalf("makeTable0EntryDirect: dLength %d is too large", dLength)
}
return uint64(rOffset)<<shiftRuneOffset |
uint64(rLength)<<shiftRuneLength |
uint64(dOffset)<<shiftDataOffset |
uint64(dLength)<<shiftDataLength |
1 // Direct bit.
}
func makeTable0EntryIndirect(rOffset, rLength, dBase, t1Offset int) uint64 {
if rOffset >= 1<<bitsRuneOffset {
log.Fatalf("makeTable0EntryIndirect: rOffset %d is too large", rOffset)
}
if rLength >= 1<<bitsRuneLength {
log.Fatalf("makeTable0EntryIndirect: rLength %d is too large", rLength)
}
if dBase >= 1<<bitsDataBase {
log.Fatalf("makeTable0EntryIndirect: dBase %d is too large", dBase)
}
if t1Offset >= 1<<bitsTable1Offset {
log.Fatalf("makeTable0EntryIndirect: t1Offset %d is too large", t1Offset)
}
return uint64(rOffset)<<shiftRuneOffset |
uint64(rLength)<<shiftRuneLength |
uint64(dBase)<<shiftDataBase |
uint64(t1Offset)<<shiftTable1Offset |
0 // Direct bit.
}
func makeTable1Entry(x int) uint16 {
if x < 0 || 0xffff < x {
log.Fatalf("makeTable1Entry: entry %d is out of range", x)
}
return uint16(x)
}
var (
data []byte
snippets = make([]snippet, 1+unicode.MaxRune)
)
func main() {
gen.Init()
names, counts := parse()
appendRepeatNames(names, counts)
appendUniqueNames(names, counts)
table0, table1 := makeTables()
gen.Repackage("gen_bits.go", "bits.go", "runenames")
w := gen.NewCodeWriter()
w.WriteVar("table0", table0)
w.WriteVar("table1", table1)
w.WriteConst("data", string(data))
w.WriteGoFile("tables.go", "runenames")
}
func parse() (names []string, counts map[string]int) {
names = make([]string, 1+unicode.MaxRune)
counts = map[string]int{}
ucd.Parse(gen.OpenUCDFile("UnicodeData.txt"), func(p *ucd.Parser) {
r, s := p.Rune(0), p.String(ucd.Name)
if s == "" {
return
}
if s[0] == '<' {
const first = ", First>"
if i := strings.Index(s, first); i >= 0 {
s = s[:i] + ">"
}
}
names[r] = s
counts[s]++
})
return names, counts
}
func appendRepeatNames(names []string, counts map[string]int) {
alreadySeen := map[string]snippet{}
for r, s := range names {
if s == "" || counts[s] == 1 {
continue
}
if s[0] != '<' {
log.Fatalf("Repeated name %q does not start with a '<'", s)
}
if z, ok := alreadySeen[s]; ok {
snippets[r] = z
continue
}
z := snippet{
offset: len(data),
length: len(s),
s: s,
}
data = append(data, s...)
snippets[r] = z
alreadySeen[s] = z
}
}
func appendUniqueNames(names []string, counts map[string]int) {
for r, s := range names {
if s == "" || counts[s] != 1 {
continue
}
if s[0] == '<' {
log.Fatalf("Unique name %q starts with a '<'", s)
}
z := snippet{
offset: len(data),
length: len(s),
s: s,
}
data = append(data, s...)
snippets[r] = z
}
}
func makeTables() (table0 []uint64, table1 []uint16) {
for i := 0; i < len(snippets); {
zi := snippets[i]
if zi == (snippet{}) {
i++
continue
}
// Look for repeat names. If we have one, we only need a table0 entry.
j := i + 1
for ; j < len(snippets) && zi == snippets[j]; j++ {
}
if j > i+1 {
table0 = append(table0, makeTable0EntryDirect(i, j-i, zi.offset, zi.length))
i = j
continue
}
// Otherwise, we have a run of unique names. We need one table0 entry
// and two or more table1 entries.
base := zi.offset &^ (1<<dataBaseUnit - 1)
t1Offset := len(table1) + 1
table1 = append(table1, makeTable1Entry(zi.offset-base))
table1 = append(table1, makeTable1Entry(zi.offset+zi.length-base))
for ; j < len(snippets) && snippets[j] != (snippet{}); j++ {
zj := snippets[j]
if data[zj.offset] == '<' {
break
}
table1 = append(table1, makeTable1Entry(zj.offset+zj.length-base))
}
table0 = append(table0, makeTable0EntryIndirect(i, j-i, base>>dataBaseUnit, t1Offset))
i = j
}
return table0, table1
}