github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/golang.org/x/text/feature/plural/plural.go (about) 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 plural provides utilities for handling linguistic plurals in text. 8 // 9 // The definitions in this package are based on the plural rule handling defined 10 // in CLDR. See 11 // https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules for 12 // details. 13 package plural 14 15 import ( 16 "golang.org/x/text/internal/language/compact" 17 "golang.org/x/text/internal/number" 18 "golang.org/x/text/language" 19 ) 20 21 // Rules defines the plural rules for all languages for a certain plural type. 22 // 23 // This package is UNDER CONSTRUCTION and its API may change. 24 type Rules struct { 25 rules []pluralCheck 26 index []byte 27 langToIndex []byte 28 inclusionMasks []uint64 29 } 30 31 var ( 32 // Cardinal defines the plural rules for numbers indicating quantities. 33 Cardinal *Rules = cardinal 34 35 // Ordinal defines the plural rules for numbers indicating position 36 // (first, second, etc.). 37 Ordinal *Rules = ordinal 38 39 ordinal = &Rules{ 40 ordinalRules, 41 ordinalIndex, 42 ordinalLangToIndex, 43 ordinalInclusionMasks[:], 44 } 45 46 cardinal = &Rules{ 47 cardinalRules, 48 cardinalIndex, 49 cardinalLangToIndex, 50 cardinalInclusionMasks[:], 51 } 52 ) 53 54 // getIntApprox converts the digits in slice digits[start:end] to an integer 55 // according to the following rules: 56 // - Let i be asInt(digits[start:end]), where out-of-range digits are assumed 57 // to be zero. 58 // - Result n is big if i / 10^nMod > 1. 59 // - Otherwise the result is i % 10^nMod. 60 // 61 // For example, if digits is {1, 2, 3} and start:end is 0:5, then the result 62 // for various values of nMod is: 63 // - when nMod == 2, n == big 64 // - when nMod == 3, n == big 65 // - when nMod == 4, n == big 66 // - when nMod == 5, n == 12300 67 // - when nMod == 6, n == 12300 68 // - when nMod == 7, n == 12300 69 func getIntApprox(digits []byte, start, end, nMod, big int) (n int) { 70 // Leading 0 digits just result in 0. 71 p := start 72 if p < 0 { 73 p = 0 74 } 75 // Range only over the part for which we have digits. 76 mid := end 77 if mid >= len(digits) { 78 mid = len(digits) 79 } 80 // Check digits more significant that nMod. 81 if q := end - nMod; q > 0 { 82 if q > mid { 83 q = mid 84 } 85 for ; p < q; p++ { 86 if digits[p] != 0 { 87 return big 88 } 89 } 90 } 91 for ; p < mid; p++ { 92 n = 10*n + int(digits[p]) 93 } 94 // Multiply for trailing zeros. 95 for ; p < end; p++ { 96 n *= 10 97 } 98 return n 99 } 100 101 // MatchDigits computes the plural form for the given language and the given 102 // decimal floating point digits. The digits are stored in big-endian order and 103 // are of value byte(0) - byte(9). The floating point position is indicated by 104 // exp and the number of visible decimals is scale. All leading and trailing 105 // zeros may be omitted from digits. 106 // 107 // The following table contains examples of possible arguments to represent 108 // the given numbers. 109 // 110 // decimal digits exp scale 111 // 123 []byte{1, 2, 3} 3 0 112 // 123.4 []byte{1, 2, 3, 4} 3 1 113 // 123.40 []byte{1, 2, 3, 4} 3 2 114 // 100000 []byte{1} 6 0 115 // 100000.00 []byte{1} 6 3 116 func (p *Rules) MatchDigits(t language.Tag, digits []byte, exp, scale int) Form { 117 index := tagToID(t) 118 119 // Differentiate up to including mod 1000000 for the integer part. 120 n := getIntApprox(digits, 0, exp, 6, 1000000) 121 122 // Differentiate up to including mod 100 for the fractional part. 123 f := getIntApprox(digits, exp, exp+scale, 2, 100) 124 125 return matchPlural(p, index, n, f, scale) 126 } 127 128 func (p *Rules) matchDisplayDigits(t language.Tag, d *number.Digits) (Form, int) { 129 n := getIntApprox(d.Digits, 0, int(d.Exp), 6, 1000000) 130 return p.MatchDigits(t, d.Digits, int(d.Exp), d.NumFracDigits()), n 131 } 132 133 func validForms(p *Rules, t language.Tag) (forms []Form) { 134 offset := p.langToIndex[tagToID(t)] 135 rules := p.rules[p.index[offset]:p.index[offset+1]] 136 137 forms = append(forms, Other) 138 last := Other 139 for _, r := range rules { 140 if cat := Form(r.cat & formMask); cat != andNext && last != cat { 141 forms = append(forms, cat) 142 last = cat 143 } 144 } 145 return forms 146 } 147 148 func (p *Rules) matchComponents(t language.Tag, n, f, scale int) Form { 149 return matchPlural(p, tagToID(t), n, f, scale) 150 } 151 152 // MatchPlural returns the plural form for the given language and plural 153 // operands (as defined in 154 // https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules): 155 // 156 // where 157 // n absolute value of the source number (integer and decimals) 158 // input 159 // i integer digits of n. 160 // v number of visible fraction digits in n, with trailing zeros. 161 // w number of visible fraction digits in n, without trailing zeros. 162 // f visible fractional digits in n, with trailing zeros (f = t * 10^(v-w)) 163 // t visible fractional digits in n, without trailing zeros. 164 // 165 // If any of the operand values is too large to fit in an int, it is okay to 166 // pass the value modulo 10,000,000. 167 func (p *Rules) MatchPlural(lang language.Tag, i, v, w, f, t int) Form { 168 return matchPlural(p, tagToID(lang), i, f, v) 169 } 170 171 func matchPlural(p *Rules, index compact.ID, n, f, v int) Form { 172 nMask := p.inclusionMasks[n%maxMod] 173 // Compute the fMask inline in the rules below, as it is relatively rare. 174 // fMask := p.inclusionMasks[f%maxMod] 175 vMask := p.inclusionMasks[v%maxMod] 176 177 // Do the matching 178 offset := p.langToIndex[index] 179 rules := p.rules[p.index[offset]:p.index[offset+1]] 180 for i := 0; i < len(rules); i++ { 181 rule := rules[i] 182 setBit := uint64(1 << rule.setID) 183 var skip bool 184 switch op := opID(rule.cat >> opShift); op { 185 case opI: // i = x 186 skip = n >= numN || nMask&setBit == 0 187 188 case opI | opNotEqual: // i != x 189 skip = n < numN && nMask&setBit != 0 190 191 case opI | opMod: // i % m = x 192 skip = nMask&setBit == 0 193 194 case opI | opMod | opNotEqual: // i % m != x 195 skip = nMask&setBit != 0 196 197 case opN: // n = x 198 skip = f != 0 || n >= numN || nMask&setBit == 0 199 200 case opN | opNotEqual: // n != x 201 skip = f == 0 && n < numN && nMask&setBit != 0 202 203 case opN | opMod: // n % m = x 204 skip = f != 0 || nMask&setBit == 0 205 206 case opN | opMod | opNotEqual: // n % m != x 207 skip = f == 0 && nMask&setBit != 0 208 209 case opF: // f = x 210 skip = f >= numN || p.inclusionMasks[f%maxMod]&setBit == 0 211 212 case opF | opNotEqual: // f != x 213 skip = f < numN && p.inclusionMasks[f%maxMod]&setBit != 0 214 215 case opF | opMod: // f % m = x 216 skip = p.inclusionMasks[f%maxMod]&setBit == 0 217 218 case opF | opMod | opNotEqual: // f % m != x 219 skip = p.inclusionMasks[f%maxMod]&setBit != 0 220 221 case opV: // v = x 222 skip = v < numN && vMask&setBit == 0 223 224 case opV | opNotEqual: // v != x 225 skip = v < numN && vMask&setBit != 0 226 227 case opW: // w == 0 228 skip = f != 0 229 230 case opW | opNotEqual: // w != 0 231 skip = f == 0 232 233 // Hard-wired rules that cannot be handled by our algorithm. 234 235 case opBretonM: 236 skip = f != 0 || n == 0 || n%1000000 != 0 237 238 case opAzerbaijan00s: 239 // 100,200,300,400,500,600,700,800,900 240 skip = n == 0 || n >= 1000 || n%100 != 0 241 242 case opItalian800: 243 skip = (f != 0 || n >= numN || nMask&setBit == 0) && n != 800 244 } 245 if skip { 246 // advance over AND entries. 247 for ; i < len(rules) && rules[i].cat&formMask == andNext; i++ { 248 } 249 continue 250 } 251 // return if we have a final entry. 252 if cat := rule.cat & formMask; cat != andNext { 253 return Form(cat) 254 } 255 } 256 return Other 257 } 258 259 func tagToID(t language.Tag) compact.ID { 260 id, _ := compact.RegionalID(compact.Tag(t)) 261 return id 262 }