taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

number.go (4827B)


      1 // Copyright 2016 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 //go:generate go run gen.go gen_common.go
      6 
      7 // Package number contains tools and data for formatting numbers.
      8 package number
      9 
     10 import (
     11 	"unicode/utf8"
     12 
     13 	"golang.org/x/text/internal/language/compact"
     14 	"golang.org/x/text/language"
     15 )
     16 
     17 // Info holds number formatting configuration data.
     18 type Info struct {
     19 	system   systemData // numbering system information
     20 	symIndex symOffset  // index to symbols
     21 }
     22 
     23 // InfoFromLangID returns a Info for the given compact language identifier and
     24 // numbering system identifier. If system is the empty string, the default
     25 // numbering system will be taken for that language.
     26 func InfoFromLangID(compactIndex compact.ID, numberSystem string) Info {
     27 	p := langToDefaults[compactIndex]
     28 	// Lookup the entry for the language.
     29 	pSymIndex := symOffset(0) // Default: Latin, default symbols
     30 	system, ok := systemMap[numberSystem]
     31 	if !ok {
     32 		// Take the value for the default numbering system. This is by far the
     33 		// most common case as an alternative numbering system is hardly used.
     34 		if p&hasNonLatnMask == 0 { // Latn digits.
     35 			pSymIndex = p
     36 		} else { // Non-Latn or multiple numbering systems.
     37 			// Take the first entry from the alternatives list.
     38 			data := langToAlt[p&^hasNonLatnMask]
     39 			pSymIndex = data.symIndex
     40 			system = data.system
     41 		}
     42 	} else {
     43 		langIndex := compactIndex
     44 		ns := system
     45 	outerLoop:
     46 		for ; ; p = langToDefaults[langIndex] {
     47 			if p&hasNonLatnMask == 0 {
     48 				if ns == 0 {
     49 					// The index directly points to the symbol data.
     50 					pSymIndex = p
     51 					break
     52 				}
     53 				// Move to the parent and retry.
     54 				langIndex = langIndex.Parent()
     55 			} else {
     56 				// The index points to a list of symbol data indexes.
     57 				for _, e := range langToAlt[p&^hasNonLatnMask:] {
     58 					if e.compactTag != langIndex {
     59 						if langIndex == 0 {
     60 							// The CLDR root defines full symbol information for
     61 							// all numbering systems (even though mostly by
     62 							// means of aliases). Fall back to the default entry
     63 							// for Latn if there is no data for the numbering
     64 							// system of this language.
     65 							if ns == 0 {
     66 								break
     67 							}
     68 							// Fall back to Latin and start from the original
     69 							// language. See
     70 							// https://unicode.org/reports/tr35/#Locale_Inheritance.
     71 							ns = numLatn
     72 							langIndex = compactIndex
     73 							continue outerLoop
     74 						}
     75 						// Fall back to parent.
     76 						langIndex = langIndex.Parent()
     77 					} else if e.system == ns {
     78 						pSymIndex = e.symIndex
     79 						break outerLoop
     80 					}
     81 				}
     82 			}
     83 		}
     84 	}
     85 	if int(system) >= len(numSysData) { // algorithmic
     86 		// Will generate ASCII digits in case the user inadvertently calls
     87 		// WriteDigit or Digit on it.
     88 		d := numSysData[0]
     89 		d.id = system
     90 		return Info{
     91 			system:   d,
     92 			symIndex: pSymIndex,
     93 		}
     94 	}
     95 	return Info{
     96 		system:   numSysData[system],
     97 		symIndex: pSymIndex,
     98 	}
     99 }
    100 
    101 // InfoFromTag returns a Info for the given language tag.
    102 func InfoFromTag(t language.Tag) Info {
    103 	return InfoFromLangID(tagToID(t), t.TypeForKey("nu"))
    104 }
    105 
    106 // IsDecimal reports if the numbering system can convert decimal to native
    107 // symbols one-to-one.
    108 func (n Info) IsDecimal() bool {
    109 	return int(n.system.id) < len(numSysData)
    110 }
    111 
    112 // WriteDigit writes the UTF-8 sequence for n corresponding to the given ASCII
    113 // digit to dst and reports the number of bytes written. dst must be large
    114 // enough to hold the rune (can be up to utf8.UTFMax bytes).
    115 func (n Info) WriteDigit(dst []byte, asciiDigit rune) int {
    116 	copy(dst, n.system.zero[:n.system.digitSize])
    117 	dst[n.system.digitSize-1] += byte(asciiDigit - '0')
    118 	return int(n.system.digitSize)
    119 }
    120 
    121 // AppendDigit appends the UTF-8 sequence for n corresponding to the given digit
    122 // to dst and reports the number of bytes written. dst must be large enough to
    123 // hold the rune (can be up to utf8.UTFMax bytes).
    124 func (n Info) AppendDigit(dst []byte, digit byte) []byte {
    125 	dst = append(dst, n.system.zero[:n.system.digitSize]...)
    126 	dst[len(dst)-1] += digit
    127 	return dst
    128 }
    129 
    130 // Digit returns the digit for the numbering system for the corresponding ASCII
    131 // value. For example, ni.Digit('3') could return 'δΈ‰'. Note that the argument
    132 // is the rune constant '3', which equals 51, not the integer constant 3.
    133 func (n Info) Digit(asciiDigit rune) rune {
    134 	var x [utf8.UTFMax]byte
    135 	n.WriteDigit(x[:], asciiDigit)
    136 	r, _ := utf8.DecodeRune(x[:])
    137 	return r
    138 }
    139 
    140 // Symbol returns the string for the given symbol type.
    141 func (n Info) Symbol(t SymbolType) string {
    142 	return symData.Elem(int(symIndex[n.symIndex][t]))
    143 }
    144 
    145 func formatForLang(t language.Tag, index []byte) *Pattern {
    146 	return &formats[index[tagToID(t)]]
    147 }
    148 
    149 func tagToID(t language.Tag) compact.ID {
    150 	id, _ := compact.RegionalID(compact.Tag(t))
    151 	return id
    152 }