OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / golang.org / x / text / language / display / lookup.go
diff --git a/vendor/golang.org/x/text/language/display/lookup.go b/vendor/golang.org/x/text/language/display/lookup.go
new file mode 100644 (file)
index 0000000..e6dc0e0
--- /dev/null
@@ -0,0 +1,251 @@
+// Copyright 2014 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.
+
+package display
+
+// This file contains common lookup code that is shared between the various
+// implementations of Namer and Dictionaries.
+
+import (
+       "fmt"
+       "sort"
+       "strings"
+
+       "golang.org/x/text/language"
+)
+
+type namer interface {
+       // name gets the string for the given index. It should walk the
+       // inheritance chain if a value is not present in the base index.
+       name(idx int) string
+}
+
+func nameLanguage(n namer, x interface{}) string {
+       t, _ := language.All.Compose(x)
+       for {
+               i, _, _ := langTagSet.index(t.Raw())
+               if s := n.name(i); s != "" {
+                       return s
+               }
+               if t = t.Parent(); t == language.Und {
+                       return ""
+               }
+       }
+}
+
+func nameScript(n namer, x interface{}) string {
+       t, _ := language.DeprecatedScript.Compose(x)
+       _, s, _ := t.Raw()
+       return n.name(scriptIndex.index(s.String()))
+}
+
+func nameRegion(n namer, x interface{}) string {
+       t, _ := language.DeprecatedRegion.Compose(x)
+       _, _, r := t.Raw()
+       return n.name(regionIndex.index(r.String()))
+}
+
+func nameTag(langN, scrN, regN namer, x interface{}) string {
+       t, ok := x.(language.Tag)
+       if !ok {
+               return ""
+       }
+       const form = language.All &^ language.SuppressScript
+       if c, err := form.Canonicalize(t); err == nil {
+               t = c
+       }
+       _, sRaw, rRaw := t.Raw()
+       i, scr, reg := langTagSet.index(t.Raw())
+       for i != -1 {
+               if str := langN.name(i); str != "" {
+                       if hasS, hasR := (scr != language.Script{}), (reg != language.Region{}); hasS || hasR {
+                               ss, sr := "", ""
+                               if hasS {
+                                       ss = scrN.name(scriptIndex.index(scr.String()))
+                               }
+                               if hasR {
+                                       sr = regN.name(regionIndex.index(reg.String()))
+                               }
+                               // TODO: use patterns in CLDR or at least confirm they are the
+                               // same for all languages.
+                               if ss != "" && sr != "" {
+                                       return fmt.Sprintf("%s (%s, %s)", str, ss, sr)
+                               }
+                               if ss != "" || sr != "" {
+                                       return fmt.Sprintf("%s (%s%s)", str, ss, sr)
+                               }
+                       }
+                       return str
+               }
+               scr, reg = sRaw, rRaw
+               if t = t.Parent(); t == language.Und {
+                       return ""
+               }
+               i, _, _ = langTagSet.index(t.Raw())
+       }
+       return ""
+}
+
+// header contains the data and indexes for a single namer.
+// data contains a series of strings concatenated into one. index contains the
+// offsets for a string in data. For example, consider a header that defines
+// strings for the languages de, el, en, fi, and nl:
+//
+//             header{
+//                     data: "GermanGreekEnglishDutch",
+//             index: []uint16{ 0, 6, 11, 18, 18, 23 },
+//             }
+//
+// For a language with index i, the string is defined by
+// data[index[i]:index[i+1]]. So the number of elements in index is always one
+// greater than the number of languages for which header defines a value.
+// A string for a language may be empty, which means the name is undefined. In
+// the above example, the name for fi (Finnish) is undefined.
+type header struct {
+       data  string
+       index []uint16
+}
+
+// name looks up the name for a tag in the dictionary, given its index.
+func (h *header) name(i int) string {
+       if 0 <= i && i < len(h.index)-1 {
+               return h.data[h.index[i]:h.index[i+1]]
+       }
+       return ""
+}
+
+// tagSet is used to find the index of a language in a set of tags.
+type tagSet struct {
+       single tagIndex
+       long   []string
+}
+
+var (
+       langTagSet = tagSet{
+               single: langIndex,
+               long:   langTagsLong,
+       }
+
+       // selfTagSet is used for indexing the language strings in their own
+       // language.
+       selfTagSet = tagSet{
+               single: selfIndex,
+               long:   selfTagsLong,
+       }
+
+       zzzz = language.MustParseScript("Zzzz")
+       zz   = language.MustParseRegion("ZZ")
+)
+
+// index returns the index of the tag for the given base, script and region or
+// its parent if the tag is not available. If the match is for a parent entry,
+// the excess script and region are returned.
+func (ts *tagSet) index(base language.Base, scr language.Script, reg language.Region) (int, language.Script, language.Region) {
+       lang := base.String()
+       index := -1
+       if (scr != language.Script{} || reg != language.Region{}) {
+               if scr == zzzz {
+                       scr = language.Script{}
+               }
+               if reg == zz {
+                       reg = language.Region{}
+               }
+
+               i := sort.SearchStrings(ts.long, lang)
+               // All entries have either a script or a region and not both.
+               scrStr, regStr := scr.String(), reg.String()
+               for ; i < len(ts.long) && strings.HasPrefix(ts.long[i], lang); i++ {
+                       if s := ts.long[i][len(lang)+1:]; s == scrStr {
+                               scr = language.Script{}
+                               index = i + ts.single.len()
+                               break
+                       } else if s == regStr {
+                               reg = language.Region{}
+                               index = i + ts.single.len()
+                               break
+                       }
+               }
+       }
+       if index == -1 {
+               index = ts.single.index(lang)
+       }
+       return index, scr, reg
+}
+
+func (ts *tagSet) Tags() []language.Tag {
+       tags := make([]language.Tag, 0, ts.single.len()+len(ts.long))
+       ts.single.keys(func(s string) {
+               tags = append(tags, language.Raw.MustParse(s))
+       })
+       for _, s := range ts.long {
+               tags = append(tags, language.Raw.MustParse(s))
+       }
+       return tags
+}
+
+func supportedScripts() []language.Script {
+       scr := make([]language.Script, 0, scriptIndex.len())
+       scriptIndex.keys(func(s string) {
+               scr = append(scr, language.MustParseScript(s))
+       })
+       return scr
+}
+
+func supportedRegions() []language.Region {
+       reg := make([]language.Region, 0, regionIndex.len())
+       regionIndex.keys(func(s string) {
+               reg = append(reg, language.MustParseRegion(s))
+       })
+       return reg
+}
+
+// tagIndex holds a concatenated lists of subtags of length 2 to 4, one string
+// for each length, which can be used in combination with binary search to get
+// the index associated with a tag.
+// For example, a tagIndex{
+//   "arenesfrruzh",  // 6 2-byte tags.
+//   "barwae",        // 2 3-byte tags.
+//   "",
+// }
+// would mean that the 2-byte tag "fr" had an index of 3, and the 3-byte tag
+// "wae" had an index of 7.
+type tagIndex [3]string
+
+func (t *tagIndex) index(s string) int {
+       sz := len(s)
+       if sz < 2 || 4 < sz {
+               return -1
+       }
+       a := t[sz-2]
+       index := sort.Search(len(a)/sz, func(i int) bool {
+               p := i * sz
+               return a[p:p+sz] >= s
+       })
+       p := index * sz
+       if end := p + sz; end > len(a) || a[p:end] != s {
+               return -1
+       }
+       // Add the number of tags for smaller sizes.
+       for i := 0; i < sz-2; i++ {
+               index += len(t[i]) / (i + 2)
+       }
+       return index
+}
+
+// len returns the number of tags that are contained in the tagIndex.
+func (t *tagIndex) len() (n int) {
+       for i, s := range t {
+               n += len(s) / (i + 2)
+       }
+       return n
+}
+
+// keys calls f for each tag.
+func (t *tagIndex) keys(f func(key string)) {
+       for i, s := range *t {
+               for ; s != ""; s = s[i+2:] {
+                       f(s[:i+2])
+               }
+       }
+}