tree.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright 2017 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. package cldrtree
  5. import (
  6. "golang.org/x/text/internal/language/compact"
  7. "golang.org/x/text/language"
  8. )
  9. const (
  10. inheritOffsetShift = 12
  11. inheritMask uint16 = 0x8000
  12. inheritValueMask uint16 = 0x0FFF
  13. missingValue uint16 = 0xFFFF
  14. )
  15. // Tree holds a tree of CLDR data.
  16. type Tree struct {
  17. Locales []uint32
  18. Indices []uint16
  19. Buckets []string
  20. }
  21. // Lookup looks up CLDR data for the given path. The lookup adheres to the alias
  22. // and locale inheritance rules as defined in CLDR.
  23. //
  24. // Each subsequent element in path indicates which subtree to select data from.
  25. // The last element of the path must select a leaf node. All other elements
  26. // of the path select a subindex.
  27. func (t *Tree) Lookup(tag compact.ID, path ...uint16) string {
  28. return t.lookup(tag, false, path...)
  29. }
  30. // LookupFeature is like Lookup, but will first check whether a value of "other"
  31. // as a fallback before traversing the inheritance chain.
  32. func (t *Tree) LookupFeature(tag compact.ID, path ...uint16) string {
  33. return t.lookup(tag, true, path...)
  34. }
  35. func (t *Tree) lookup(tag compact.ID, isFeature bool, path ...uint16) string {
  36. origLang := tag
  37. outer:
  38. for {
  39. index := t.Indices[t.Locales[tag]:]
  40. k := uint16(0)
  41. for i := range path {
  42. max := index[k]
  43. if i < len(path)-1 {
  44. // index (non-leaf)
  45. if path[i] >= max {
  46. break
  47. }
  48. k = index[k+1+path[i]]
  49. if k == 0 {
  50. break
  51. }
  52. if v := k &^ inheritMask; k != v {
  53. offset := v >> inheritOffsetShift
  54. value := v & inheritValueMask
  55. path[uint16(i)-offset] = value
  56. tag = origLang
  57. continue outer
  58. }
  59. } else {
  60. // leaf value
  61. offset := missingValue
  62. if path[i] < max {
  63. offset = index[k+2+path[i]]
  64. }
  65. if offset == missingValue {
  66. if !isFeature {
  67. break
  68. }
  69. // "other" feature must exist
  70. offset = index[k+2]
  71. }
  72. data := t.Buckets[index[k+1]]
  73. n := uint16(data[offset])
  74. return data[offset+1 : offset+n+1]
  75. }
  76. }
  77. if tag == 0 {
  78. break
  79. }
  80. tag = tag.Parent()
  81. }
  82. return ""
  83. }
  84. func build(b *Builder) (*Tree, error) {
  85. var t Tree
  86. t.Locales = make([]uint32, language.NumCompactTags)
  87. for _, loc := range b.locales {
  88. tag, _ := language.CompactIndex(loc.tag)
  89. t.Locales[tag] = uint32(len(t.Indices))
  90. var x indexBuilder
  91. x.add(loc.root)
  92. t.Indices = append(t.Indices, x.index...)
  93. }
  94. // Set locales for which we don't have data to the parent's data.
  95. for i, v := range t.Locales {
  96. p := compact.ID(i)
  97. for v == 0 && p != 0 {
  98. p = p.Parent()
  99. v = t.Locales[p]
  100. }
  101. t.Locales[i] = v
  102. }
  103. for _, b := range b.buckets {
  104. t.Buckets = append(t.Buckets, string(b))
  105. }
  106. if b.err != nil {
  107. return nil, b.err
  108. }
  109. return &t, nil
  110. }
  111. type indexBuilder struct {
  112. index []uint16
  113. }
  114. func (b *indexBuilder) add(i *Index) uint16 {
  115. offset := len(b.index)
  116. max := enumIndex(0)
  117. switch {
  118. case len(i.values) > 0:
  119. for _, v := range i.values {
  120. if v.key > max {
  121. max = v.key
  122. }
  123. }
  124. b.index = append(b.index, make([]uint16, max+3)...)
  125. b.index[offset] = uint16(max) + 1
  126. b.index[offset+1] = i.values[0].value.bucket
  127. for i := offset + 2; i < len(b.index); i++ {
  128. b.index[i] = missingValue
  129. }
  130. for _, v := range i.values {
  131. b.index[offset+2+int(v.key)] = v.value.bucketPos
  132. }
  133. return uint16(offset)
  134. case len(i.subIndex) > 0:
  135. for _, s := range i.subIndex {
  136. if s.meta.index > max {
  137. max = s.meta.index
  138. }
  139. }
  140. b.index = append(b.index, make([]uint16, max+2)...)
  141. b.index[offset] = uint16(max) + 1
  142. for _, s := range i.subIndex {
  143. x := b.add(s)
  144. b.index[offset+int(s.meta.index)+1] = x
  145. }
  146. return uint16(offset)
  147. case i.meta.inheritOffset < 0:
  148. v := uint16(-(i.meta.inheritOffset + 1)) << inheritOffsetShift
  149. p := i.meta
  150. for k := i.meta.inheritOffset; k < 0; k++ {
  151. p = p.parent
  152. }
  153. v += uint16(p.typeInfo.enum.lookup(i.meta.inheritIndex))
  154. v |= inheritMask
  155. return v
  156. }
  157. return 0
  158. }