123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // Copyright 2018 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 language
- import (
- "sort"
- "strings"
- )
- // A Builder allows constructing a Tag from individual components.
- // Its main user is Compose in the top-level language package.
- type Builder struct {
- Tag Tag
- private string // the x extension
- variants []string
- extensions []string
- }
- // Make returns a new Tag from the current settings.
- func (b *Builder) Make() Tag {
- t := b.Tag
- if len(b.extensions) > 0 || len(b.variants) > 0 {
- sort.Sort(sortVariants(b.variants))
- sort.Strings(b.extensions)
- if b.private != "" {
- b.extensions = append(b.extensions, b.private)
- }
- n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)
- buf := make([]byte, n)
- p := t.genCoreBytes(buf)
- t.pVariant = byte(p)
- p += appendTokens(buf[p:], b.variants...)
- t.pExt = uint16(p)
- p += appendTokens(buf[p:], b.extensions...)
- t.str = string(buf[:p])
- // We may not always need to remake the string, but when or when not
- // to do so is rather tricky.
- scan := makeScanner(buf[:p])
- t, _ = parse(&scan, "")
- return t
- } else if b.private != "" {
- t.str = b.private
- t.RemakeString()
- }
- return t
- }
- // SetTag copies all the settings from a given Tag. Any previously set values
- // are discarded.
- func (b *Builder) SetTag(t Tag) {
- b.Tag.LangID = t.LangID
- b.Tag.RegionID = t.RegionID
- b.Tag.ScriptID = t.ScriptID
- // TODO: optimize
- b.variants = b.variants[:0]
- if variants := t.Variants(); variants != "" {
- for _, vr := range strings.Split(variants[1:], "-") {
- b.variants = append(b.variants, vr)
- }
- }
- b.extensions, b.private = b.extensions[:0], ""
- for _, e := range t.Extensions() {
- b.AddExt(e)
- }
- }
- // AddExt adds extension e to the tag. e must be a valid extension as returned
- // by Tag.Extension. If the extension already exists, it will be discarded,
- // except for a -u extension, where non-existing key-type pairs will added.
- func (b *Builder) AddExt(e string) {
- if e[0] == 'x' {
- if b.private == "" {
- b.private = e
- }
- return
- }
- for i, s := range b.extensions {
- if s[0] == e[0] {
- if e[0] == 'u' {
- b.extensions[i] += e[1:]
- }
- return
- }
- }
- b.extensions = append(b.extensions, e)
- }
- // SetExt sets the extension e to the tag. e must be a valid extension as
- // returned by Tag.Extension. If the extension already exists, it will be
- // overwritten, except for a -u extension, where the individual key-type pairs
- // will be set.
- func (b *Builder) SetExt(e string) {
- if e[0] == 'x' {
- b.private = e
- return
- }
- for i, s := range b.extensions {
- if s[0] == e[0] {
- if e[0] == 'u' {
- b.extensions[i] = e + s[1:]
- } else {
- b.extensions[i] = e
- }
- return
- }
- }
- b.extensions = append(b.extensions, e)
- }
- // AddVariant adds any number of variants.
- func (b *Builder) AddVariant(v ...string) {
- for _, v := range v {
- if v != "" {
- b.variants = append(b.variants, v)
- }
- }
- }
- // ClearVariants removes any variants previously added, including those
- // copied from a Tag in SetTag.
- func (b *Builder) ClearVariants() {
- b.variants = b.variants[:0]
- }
- // ClearExtensions removes any extensions previously added, including those
- // copied from a Tag in SetTag.
- func (b *Builder) ClearExtensions() {
- b.private = ""
- b.extensions = b.extensions[:0]
- }
- func tokenLen(token ...string) (n int) {
- for _, t := range token {
- n += len(t) + 1
- }
- return
- }
- func appendTokens(b []byte, token ...string) int {
- p := 0
- for _, t := range token {
- b[p] = '-'
- copy(b[p+1:], t)
- p += 1 + len(t)
- }
- return p
- }
- type sortVariants []string
- func (s sortVariants) Len() int {
- return len(s)
- }
- func (s sortVariants) Swap(i, j int) {
- s[j], s[i] = s[i], s[j]
- }
- func (s sortVariants) Less(i, j int) bool {
- return variantIndex[s[i]] < variantIndex[s[j]]
- }
|