compose.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2018 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 language
  5. import (
  6. "sort"
  7. "strings"
  8. )
  9. // A Builder allows constructing a Tag from individual components.
  10. // Its main user is Compose in the top-level language package.
  11. type Builder struct {
  12. Tag Tag
  13. private string // the x extension
  14. variants []string
  15. extensions []string
  16. }
  17. // Make returns a new Tag from the current settings.
  18. func (b *Builder) Make() Tag {
  19. t := b.Tag
  20. if len(b.extensions) > 0 || len(b.variants) > 0 {
  21. sort.Sort(sortVariants(b.variants))
  22. sort.Strings(b.extensions)
  23. if b.private != "" {
  24. b.extensions = append(b.extensions, b.private)
  25. }
  26. n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)
  27. buf := make([]byte, n)
  28. p := t.genCoreBytes(buf)
  29. t.pVariant = byte(p)
  30. p += appendTokens(buf[p:], b.variants...)
  31. t.pExt = uint16(p)
  32. p += appendTokens(buf[p:], b.extensions...)
  33. t.str = string(buf[:p])
  34. // We may not always need to remake the string, but when or when not
  35. // to do so is rather tricky.
  36. scan := makeScanner(buf[:p])
  37. t, _ = parse(&scan, "")
  38. return t
  39. } else if b.private != "" {
  40. t.str = b.private
  41. t.RemakeString()
  42. }
  43. return t
  44. }
  45. // SetTag copies all the settings from a given Tag. Any previously set values
  46. // are discarded.
  47. func (b *Builder) SetTag(t Tag) {
  48. b.Tag.LangID = t.LangID
  49. b.Tag.RegionID = t.RegionID
  50. b.Tag.ScriptID = t.ScriptID
  51. // TODO: optimize
  52. b.variants = b.variants[:0]
  53. if variants := t.Variants(); variants != "" {
  54. for _, vr := range strings.Split(variants[1:], "-") {
  55. b.variants = append(b.variants, vr)
  56. }
  57. }
  58. b.extensions, b.private = b.extensions[:0], ""
  59. for _, e := range t.Extensions() {
  60. b.AddExt(e)
  61. }
  62. }
  63. // AddExt adds extension e to the tag. e must be a valid extension as returned
  64. // by Tag.Extension. If the extension already exists, it will be discarded,
  65. // except for a -u extension, where non-existing key-type pairs will added.
  66. func (b *Builder) AddExt(e string) {
  67. if e[0] == 'x' {
  68. if b.private == "" {
  69. b.private = e
  70. }
  71. return
  72. }
  73. for i, s := range b.extensions {
  74. if s[0] == e[0] {
  75. if e[0] == 'u' {
  76. b.extensions[i] += e[1:]
  77. }
  78. return
  79. }
  80. }
  81. b.extensions = append(b.extensions, e)
  82. }
  83. // SetExt sets the extension e to the tag. e must be a valid extension as
  84. // returned by Tag.Extension. If the extension already exists, it will be
  85. // overwritten, except for a -u extension, where the individual key-type pairs
  86. // will be set.
  87. func (b *Builder) SetExt(e string) {
  88. if e[0] == 'x' {
  89. b.private = e
  90. return
  91. }
  92. for i, s := range b.extensions {
  93. if s[0] == e[0] {
  94. if e[0] == 'u' {
  95. b.extensions[i] = e + s[1:]
  96. } else {
  97. b.extensions[i] = e
  98. }
  99. return
  100. }
  101. }
  102. b.extensions = append(b.extensions, e)
  103. }
  104. // AddVariant adds any number of variants.
  105. func (b *Builder) AddVariant(v ...string) {
  106. for _, v := range v {
  107. if v != "" {
  108. b.variants = append(b.variants, v)
  109. }
  110. }
  111. }
  112. // ClearVariants removes any variants previously added, including those
  113. // copied from a Tag in SetTag.
  114. func (b *Builder) ClearVariants() {
  115. b.variants = b.variants[:0]
  116. }
  117. // ClearExtensions removes any extensions previously added, including those
  118. // copied from a Tag in SetTag.
  119. func (b *Builder) ClearExtensions() {
  120. b.private = ""
  121. b.extensions = b.extensions[:0]
  122. }
  123. func tokenLen(token ...string) (n int) {
  124. for _, t := range token {
  125. n += len(t) + 1
  126. }
  127. return
  128. }
  129. func appendTokens(b []byte, token ...string) int {
  130. p := 0
  131. for _, t := range token {
  132. b[p] = '-'
  133. copy(b[p+1:], t)
  134. p += 1 + len(t)
  135. }
  136. return p
  137. }
  138. type sortVariants []string
  139. func (s sortVariants) Len() int {
  140. return len(s)
  141. }
  142. func (s sortVariants) Swap(i, j int) {
  143. s[j], s[i] = s[i], s[j]
  144. }
  145. func (s sortVariants) Less(i, j int) bool {
  146. return variantIndex[s[i]] < variantIndex[s[j]]
  147. }