github.com/go-xe2/third@v1.0.3/golang.org/x/text/internal/cldrtree/tree.go (about)

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