OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / feature / plural / plural.go
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 // http://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/number"
17         "golang.org/x/text/language"
18 )
19
20 // Rules defines the plural rules for all languages for a certain plural type.
21 //
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 //      decimal    digits              exp    scale
110 //      123        []byte{1, 2, 3}     3      0
111 //      123.4      []byte{1, 2, 3, 4}  3      1
112 //      123.40     []byte{1, 2, 3, 4}  3      2
113 //      100000     []byte{1}           6      0
114 //      100000.00  []byte{1}           6      3
115 func (p *Rules) MatchDigits(t language.Tag, digits []byte, exp, scale int) Form {
116         index, _ := language.CompactIndex(t)
117
118         // Differentiate up to including mod 1000000 for the integer part.
119         n := getIntApprox(digits, 0, exp, 6, 1000000)
120
121         // Differentiate up to including mod 100 for the fractional part.
122         f := getIntApprox(digits, exp, exp+scale, 2, 100)
123
124         return matchPlural(p, index, n, f, scale)
125 }
126
127 func (p *Rules) matchDisplayDigits(t language.Tag, d *number.Digits) (Form, int) {
128         n := getIntApprox(d.Digits, 0, int(d.Exp), 6, 1000000)
129         return p.MatchDigits(t, d.Digits, int(d.Exp), d.NumFracDigits()), n
130 }
131
132 func validForms(p *Rules, t language.Tag) (forms []Form) {
133         index, _ := language.CompactIndex(t)
134         offset := p.langToIndex[index]
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         index, _ := language.CompactIndex(t)
150         return matchPlural(p, index, n, f, scale)
151 }
152
153 // MatchPlural returns the plural form for the given language and plural
154 // operands (as defined in
155 // http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules):
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         index, _ := language.CompactIndex(lang)
169         return matchPlural(p, index, i, f, v)
170 }
171
172 func matchPlural(p *Rules, index int, n, f, v int) Form {
173         nMask := p.inclusionMasks[n%maxMod]
174         // Compute the fMask inline in the rules below, as it is relatively rare.
175         // fMask := p.inclusionMasks[f%maxMod]
176         vMask := p.inclusionMasks[v%maxMod]
177
178         // Do the matching
179         offset := p.langToIndex[index]
180         rules := p.rules[p.index[offset]:p.index[offset+1]]
181         for i := 0; i < len(rules); i++ {
182                 rule := rules[i]
183                 setBit := uint64(1 << rule.setID)
184                 var skip bool
185                 switch op := opID(rule.cat >> opShift); op {
186                 case opI: // i = x
187                         skip = n >= numN || nMask&setBit == 0
188
189                 case opI | opNotEqual: // i != x
190                         skip = n < numN && nMask&setBit != 0
191
192                 case opI | opMod: // i % m = x
193                         skip = nMask&setBit == 0
194
195                 case opI | opMod | opNotEqual: // i % m != x
196                         skip = nMask&setBit != 0
197
198                 case opN: // n = x
199                         skip = f != 0 || n >= numN || nMask&setBit == 0
200
201                 case opN | opNotEqual: // n != x
202                         skip = f == 0 && n < numN && nMask&setBit != 0
203
204                 case opN | opMod: // n % m = x
205                         skip = f != 0 || nMask&setBit == 0
206
207                 case opN | opMod | opNotEqual: // n % m != x
208                         skip = f == 0 && nMask&setBit != 0
209
210                 case opF: // f = x
211                         skip = f >= numN || p.inclusionMasks[f%maxMod]&setBit == 0
212
213                 case opF | opNotEqual: // f != x
214                         skip = f < numN && p.inclusionMasks[f%maxMod]&setBit != 0
215
216                 case opF | opMod: // f % m = x
217                         skip = p.inclusionMasks[f%maxMod]&setBit == 0
218
219                 case opF | opMod | opNotEqual: // f % m != x
220                         skip = p.inclusionMasks[f%maxMod]&setBit != 0
221
222                 case opV: // v = x
223                         skip = v < numN && vMask&setBit == 0
224
225                 case opV | opNotEqual: // v != x
226                         skip = v < numN && vMask&setBit != 0
227
228                 case opW: // w == 0
229                         skip = f != 0
230
231                 case opW | opNotEqual: // w != 0
232                         skip = f == 0
233
234                 // Hard-wired rules that cannot be handled by our algorithm.
235
236                 case opBretonM:
237                         skip = f != 0 || n == 0 || n%1000000 != 0
238
239                 case opAzerbaijan00s:
240                         // 100,200,300,400,500,600,700,800,900
241                         skip = n == 0 || n >= 1000 || n%100 != 0
242
243                 case opItalian800:
244                         skip = (f != 0 || n >= numN || nMask&setBit == 0) && n != 800
245                 }
246                 if skip {
247                         // advance over AND entries.
248                         for ; i < len(rules) && rules[i].cat&formMask == andNext; i++ {
249                         }
250                         continue
251                 }
252                 // return if we have a final entry.
253                 if cat := rule.cat & formMask; cat != andNext {
254                         return Form(cat)
255                 }
256         }
257         return Other
258 }