Path: blob/main/vendor/golang.org/x/text/internal/language/compose.go
2893 views
// Copyright 2018 The Go Authors. All rights reserved.1// Use of this source code is governed by a BSD-style2// license that can be found in the LICENSE file.34package language56import (7"sort"8"strings"9)1011// A Builder allows constructing a Tag from individual components.12// Its main user is Compose in the top-level language package.13type Builder struct {14Tag Tag1516private string // the x extension17variants []string18extensions []string19}2021// Make returns a new Tag from the current settings.22func (b *Builder) Make() Tag {23t := b.Tag2425if len(b.extensions) > 0 || len(b.variants) > 0 {26sort.Sort(sortVariants(b.variants))27sort.Strings(b.extensions)2829if b.private != "" {30b.extensions = append(b.extensions, b.private)31}32n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)33buf := make([]byte, n)34p := t.genCoreBytes(buf)35t.pVariant = byte(p)36p += appendTokens(buf[p:], b.variants...)37t.pExt = uint16(p)38p += appendTokens(buf[p:], b.extensions...)39t.str = string(buf[:p])40// We may not always need to remake the string, but when or when not41// to do so is rather tricky.42scan := makeScanner(buf[:p])43t, _ = parse(&scan, "")44return t4546} else if b.private != "" {47t.str = b.private48t.RemakeString()49}50return t51}5253// SetTag copies all the settings from a given Tag. Any previously set values54// are discarded.55func (b *Builder) SetTag(t Tag) {56b.Tag.LangID = t.LangID57b.Tag.RegionID = t.RegionID58b.Tag.ScriptID = t.ScriptID59// TODO: optimize60b.variants = b.variants[:0]61if variants := t.Variants(); variants != "" {62for _, vr := range strings.Split(variants[1:], "-") {63b.variants = append(b.variants, vr)64}65}66b.extensions, b.private = b.extensions[:0], ""67for _, e := range t.Extensions() {68b.AddExt(e)69}70}7172// AddExt adds extension e to the tag. e must be a valid extension as returned73// by Tag.Extension. If the extension already exists, it will be discarded,74// except for a -u extension, where non-existing key-type pairs will added.75func (b *Builder) AddExt(e string) {76if e[0] == 'x' {77if b.private == "" {78b.private = e79}80return81}82for i, s := range b.extensions {83if s[0] == e[0] {84if e[0] == 'u' {85b.extensions[i] += e[1:]86}87return88}89}90b.extensions = append(b.extensions, e)91}9293// SetExt sets the extension e to the tag. e must be a valid extension as94// returned by Tag.Extension. If the extension already exists, it will be95// overwritten, except for a -u extension, where the individual key-type pairs96// will be set.97func (b *Builder) SetExt(e string) {98if e[0] == 'x' {99b.private = e100return101}102for i, s := range b.extensions {103if s[0] == e[0] {104if e[0] == 'u' {105b.extensions[i] = e + s[1:]106} else {107b.extensions[i] = e108}109return110}111}112b.extensions = append(b.extensions, e)113}114115// AddVariant adds any number of variants.116func (b *Builder) AddVariant(v ...string) {117for _, v := range v {118if v != "" {119b.variants = append(b.variants, v)120}121}122}123124// ClearVariants removes any variants previously added, including those125// copied from a Tag in SetTag.126func (b *Builder) ClearVariants() {127b.variants = b.variants[:0]128}129130// ClearExtensions removes any extensions previously added, including those131// copied from a Tag in SetTag.132func (b *Builder) ClearExtensions() {133b.private = ""134b.extensions = b.extensions[:0]135}136137func tokenLen(token ...string) (n int) {138for _, t := range token {139n += len(t) + 1140}141return142}143144func appendTokens(b []byte, token ...string) int {145p := 0146for _, t := range token {147b[p] = '-'148copy(b[p+1:], t)149p += 1 + len(t)150}151return p152}153154type sortVariants []string155156func (s sortVariants) Len() int {157return len(s)158}159160func (s sortVariants) Swap(i, j int) {161s[j], s[i] = s[i], s[j]162}163164func (s sortVariants) Less(i, j int) bool {165return variantIndex[s[i]] < variantIndex[s[j]]166}167168169