| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package number |
| |
| import "golang.org/x/text/internal/format/plural" |
| |
| type pluralRules struct { |
| rules []pluralCheck |
| index []byte |
| langToIndex []byte |
| inclusionMasks []uint64 |
| } |
| |
| var ( |
| ordinalData = pluralRules{ |
| ordinalRules, |
| ordinalIndex, |
| ordinalLangToIndex, |
| ordinalInclusionMasks[:], |
| } |
| cardinalData = pluralRules{ |
| cardinalRules, |
| cardinalIndex, |
| cardinalLangToIndex, |
| cardinalInclusionMasks[:], |
| } |
| ) |
| |
| // See gen_plural.go for an explanation of the algorithm. |
| |
| func matchPlural(p *pluralRules, index int, n, f, v int) plural.Form { |
| nMask := p.inclusionMasks[n%maxMod] |
| // Compute the fMask inline in the rules below, as it is relatively rare. |
| // fMask := p.inclusionMasks[f%maxMod] |
| vMask := p.inclusionMasks[v%maxMod] |
| |
| // Do the matching |
| offset := p.langToIndex[index] |
| rules := p.rules[p.index[offset]:p.index[offset+1]] |
| for i := 0; i < len(rules); i++ { |
| rule := rules[i] |
| setBit := uint64(1 << rule.setID) |
| var skip bool |
| switch op := opID(rule.cat >> opShift); op { |
| case opI: // i = x |
| skip = n >= numN || nMask&setBit == 0 |
| |
| case opI | opNotEqual: // i != x |
| skip = n < numN && nMask&setBit != 0 |
| |
| case opI | opMod: // i % m = x |
| skip = nMask&setBit == 0 |
| |
| case opI | opMod | opNotEqual: // i % m != x |
| skip = nMask&setBit != 0 |
| |
| case opN: // n = x |
| skip = f != 0 || n >= numN || nMask&setBit == 0 |
| |
| case opN | opNotEqual: // n != x |
| skip = f == 0 && n < numN && nMask&setBit != 0 |
| |
| case opN | opMod: // n % m = x |
| skip = f != 0 || nMask&setBit == 0 |
| |
| case opN | opMod | opNotEqual: // n % m != x |
| skip = f == 0 && nMask&setBit != 0 |
| |
| case opF: // f = x |
| skip = f >= numN || p.inclusionMasks[f%maxMod]&setBit == 0 |
| |
| case opF | opNotEqual: // f != x |
| skip = f < numN && p.inclusionMasks[f%maxMod]&setBit != 0 |
| |
| case opF | opMod: // f % m = x |
| skip = p.inclusionMasks[f%maxMod]&setBit == 0 |
| |
| case opF | opMod | opNotEqual: // f % m != x |
| skip = p.inclusionMasks[f%maxMod]&setBit != 0 |
| |
| case opV: // v = x |
| skip = v < numN && vMask&setBit == 0 |
| |
| case opV | opNotEqual: // v != x |
| skip = v < numN && vMask&setBit != 0 |
| |
| case opW: // w == 0 |
| skip = f != 0 |
| |
| case opW | opNotEqual: // w != 0 |
| skip = f == 0 |
| |
| // Hard-wired rules that cannot be handled by our algorithm. |
| |
| case opBretonM: |
| skip = f != 0 || n == 0 || n%1000000 != 0 |
| |
| case opAzerbaijan00s: |
| // 100,200,300,400,500,600,700,800,900 |
| skip = n == 0 || n >= 1000 || n%100 != 0 |
| |
| case opItalian800: |
| skip = (f != 0 || n >= numN || nMask&setBit == 0) && n != 800 |
| } |
| if skip { |
| // advance over AND entries. |
| for ; i < len(rules) && rules[i].cat&formMask == andNext; i++ { |
| } |
| continue |
| } |
| // return if we have a final entry. |
| if cat := rule.cat & formMask; cat != andNext { |
| return plural.Form(cat) |
| } |
| } |
| return plural.Other |
| } |