1
2
3
4
5
6
7
8
9
10
11
12
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
22
23
24 type Rules struct {
25 rules []pluralCheck
26 index []byte
27 langToIndex []byte
28 inclusionMasks []uint64
29 }
30
31 var (
32
33 Cardinal *Rules = cardinal
34
35
36
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 func getIntApprox(digits []byte, start, end, nMod, big int) (n int) {
70
71 p := start
72 if p < 0 {
73 p = 0
74 }
75
76 mid := end
77 if mid >= len(digits) {
78 mid = len(digits)
79 }
80
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
95 for ; p < end; p++ {
96 n *= 10
97 }
98 return n
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 func (p *Rules) MatchDigits(t language.Tag, digits []byte, exp, scale int) Form {
117 index := tagToID(t)
118
119
120 n := getIntApprox(digits, 0, exp, 6, 1000000)
121
122
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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
174
175 vMask := p.inclusionMasks[v%maxMod]
176
177
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:
186 skip = n >= numN || nMask&setBit == 0
187
188 case opI | opNotEqual:
189 skip = n < numN && nMask&setBit != 0
190
191 case opI | opMod:
192 skip = nMask&setBit == 0
193
194 case opI | opMod | opNotEqual:
195 skip = nMask&setBit != 0
196
197 case opN:
198 skip = f != 0 || n >= numN || nMask&setBit == 0
199
200 case opN | opNotEqual:
201 skip = f == 0 && n < numN && nMask&setBit != 0
202
203 case opN | opMod:
204 skip = f != 0 || nMask&setBit == 0
205
206 case opN | opMod | opNotEqual:
207 skip = f == 0 && nMask&setBit != 0
208
209 case opF:
210 skip = f >= numN || p.inclusionMasks[f%maxMod]&setBit == 0
211
212 case opF | opNotEqual:
213 skip = f < numN && p.inclusionMasks[f%maxMod]&setBit != 0
214
215 case opF | opMod:
216 skip = p.inclusionMasks[f%maxMod]&setBit == 0
217
218 case opF | opMod | opNotEqual:
219 skip = p.inclusionMasks[f%maxMod]&setBit != 0
220
221 case opV:
222 skip = v < numN && vMask&setBit == 0
223
224 case opV | opNotEqual:
225 skip = v < numN && vMask&setBit != 0
226
227 case opW:
228 skip = f != 0
229
230 case opW | opNotEqual:
231 skip = f == 0
232
233
234
235 case opBretonM:
236 skip = f != 0 || n == 0 || n%1000000 != 0
237
238 case opAzerbaijan00s:
239
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
247 for ; i < len(rules) && rules[i].cat&formMask == andNext; i++ {
248 }
249 continue
250 }
251
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 }
263
View as plain text