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