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.
13package plural
14
15import (
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.
24type Rules struct {
25	rules          []pluralCheck
26	index          []byte
27	langToIndex    []byte
28	inclusionMasks []uint64
29}
30
31var (
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
69func 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
115func (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
127func (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
132func 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
148func (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.
167func (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
172func 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}
259