| // Copyright 2014 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. |
| |
| //go:build ignore |
| // +build ignore |
| |
| package main |
| |
| // This file contains definitions for interpreting the trie value of the case |
| // trie generated by "go run gen*.go". It is shared by both the generator |
| // program and the resultant package. Sharing is achieved by the generator |
| // copying gen_trieval.go to trieval.go and changing what's above this comment. |
| |
| // info holds case information for a single rune. It is the value returned |
| // by a trie lookup. Most mapping information can be stored in a single 16-bit |
| // value. If not, for example when a rune is mapped to multiple runes, the value |
| // stores some basic case data and an index into an array with additional data. |
| // |
| // The per-rune values have the following format: |
| // |
| // if (exception) { |
| // 15..4 unsigned exception index |
| // } else { |
| // 15..8 XOR pattern or index to XOR pattern for case mapping |
| // Only 13..8 are used for XOR patterns. |
| // 7 inverseFold (fold to upper, not to lower) |
| // 6 index: interpret the XOR pattern as an index |
| // or isMid if case mode is cIgnorableUncased. |
| // 5..4 CCC: zero (normal or break), above or other |
| // } |
| // 3 exception: interpret this value as an exception index |
| // (TODO: is this bit necessary? Probably implied from case mode.) |
| // 2..0 case mode |
| // |
| // For the non-exceptional cases, a rune must be either uncased, lowercase or |
| // uppercase. If the rune is cased, the XOR pattern maps either a lowercase |
| // rune to uppercase or an uppercase rune to lowercase (applied to the 10 |
| // least-significant bits of the rune). |
| // |
| // See the definitions below for a more detailed description of the various |
| // bits. |
| type info uint16 |
| |
| const ( |
| casedMask = 0x0003 |
| fullCasedMask = 0x0007 |
| ignorableMask = 0x0006 |
| ignorableValue = 0x0004 |
| |
| inverseFoldBit = 1 << 7 |
| isMidBit = 1 << 6 |
| |
| exceptionBit = 1 << 3 |
| exceptionShift = 4 |
| numExceptionBits = 12 |
| |
| xorIndexBit = 1 << 6 |
| xorShift = 8 |
| |
| // There is no mapping if all xor bits and the exception bit are zero. |
| hasMappingMask = 0xff80 | exceptionBit |
| ) |
| |
| // The case mode bits encodes the case type of a rune. This includes uncased, |
| // title, upper and lower case and case ignorable. (For a definition of these |
| // terms see Chapter 3 of The Unicode Standard Core Specification.) In some rare |
| // cases, a rune can be both cased and case-ignorable. This is encoded by |
| // cIgnorableCased. A rune of this type is always lower case. Some runes are |
| // cased while not having a mapping. |
| // |
| // A common pattern for scripts in the Unicode standard is for upper and lower |
| // case runes to alternate for increasing rune values (e.g. the accented Latin |
| // ranges starting from U+0100 and U+1E00 among others and some Cyrillic |
| // characters). We use this property by defining a cXORCase mode, where the case |
| // mode (always upper or lower case) is derived from the rune value. As the XOR |
| // pattern for case mappings is often identical for successive runes, using |
| // cXORCase can result in large series of identical trie values. This, in turn, |
| // allows us to better compress the trie blocks. |
| const ( |
| cUncased info = iota // 000 |
| cTitle // 001 |
| cLower // 010 |
| cUpper // 011 |
| cIgnorableUncased // 100 |
| cIgnorableCased // 101 // lower case if mappings exist |
| cXORCase // 11x // case is cLower | ((rune&1) ^ x) |
| |
| maxCaseMode = cUpper |
| ) |
| |
| func (c info) isCased() bool { |
| return c&casedMask != 0 |
| } |
| |
| func (c info) isCaseIgnorable() bool { |
| return c&ignorableMask == ignorableValue |
| } |
| |
| func (c info) isNotCasedAndNotCaseIgnorable() bool { |
| return c&fullCasedMask == 0 |
| } |
| |
| func (c info) isCaseIgnorableAndNotCased() bool { |
| return c&fullCasedMask == cIgnorableUncased |
| } |
| |
| func (c info) isMid() bool { |
| return c&(fullCasedMask|isMidBit) == isMidBit|cIgnorableUncased |
| } |
| |
| // The case mapping implementation will need to know about various Canonical |
| // Combining Class (CCC) values. We encode two of these in the trie value: |
| // cccZero (0) and cccAbove (230). If the value is cccOther, it means that |
| // CCC(r) > 0, but not 230. A value of cccBreak means that CCC(r) == 0 and that |
| // the rune also has the break category Break (see below). |
| const ( |
| cccBreak info = iota << 4 |
| cccZero |
| cccAbove |
| cccOther |
| |
| cccMask = cccBreak | cccZero | cccAbove | cccOther |
| ) |
| |
| const ( |
| starter = 0 |
| above = 230 |
| iotaSubscript = 240 |
| ) |
| |
| // The exceptions slice holds data that does not fit in a normal info entry. |
| // The entry is pointed to by the exception index in an entry. It has the |
| // following format: |
| // |
| // Header: |
| // |
| // byte 0: |
| // 7..6 unused |
| // 5..4 CCC type (same bits as entry) |
| // 3 unused |
| // 2..0 length of fold |
| // |
| // byte 1: |
| // 7..6 unused |
| // 5..3 length of 1st mapping of case type |
| // 2..0 length of 2nd mapping of case type |
| // |
| // case 1st 2nd |
| // lower -> upper, title |
| // upper -> lower, title |
| // title -> lower, upper |
| // |
| // Lengths with the value 0x7 indicate no value and implies no change. |
| // A length of 0 indicates a mapping to zero-length string. |
| // |
| // Body bytes: |
| // |
| // case folding bytes |
| // lowercase mapping bytes |
| // uppercase mapping bytes |
| // titlecase mapping bytes |
| // closure mapping bytes (for NFKC_Casefold). (TODO) |
| // |
| // Fallbacks: |
| // |
| // missing fold -> lower |
| // missing title -> upper |
| // all missing -> original rune |
| // |
| // exceptions starts with a dummy byte to enforce that there is no zero index |
| // value. |
| const ( |
| lengthMask = 0x07 |
| lengthBits = 3 |
| noChange = 0 |
| ) |
| |
| // References to generated trie. |
| |
| var trie = newCaseTrie(0) |
| |
| var sparse = sparseBlocks{ |
| values: sparseValues[:], |
| offsets: sparseOffsets[:], |
| } |
| |
| // Sparse block lookup code. |
| |
| // valueRange is an entry in a sparse block. |
| type valueRange struct { |
| value uint16 |
| lo, hi byte |
| } |
| |
| type sparseBlocks struct { |
| values []valueRange |
| offsets []uint16 |
| } |
| |
| // lookup returns the value from values block n for byte b using binary search. |
| func (s *sparseBlocks) lookup(n uint32, b byte) uint16 { |
| lo := s.offsets[n] |
| hi := s.offsets[n+1] |
| for lo < hi { |
| m := lo + (hi-lo)/2 |
| r := s.values[m] |
| if r.lo <= b && b <= r.hi { |
| return r.value |
| } |
| if b < r.lo { |
| hi = m |
| } else { |
| lo = m + 1 |
| } |
| } |
| return 0 |
| } |
| |
| // lastRuneForTesting is the last rune used for testing. Everything after this |
| // is boring. |
| const lastRuneForTesting = rune(0x1FFFF) |