OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / unicode / bidi / prop.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 package bidi
6
7 import "unicode/utf8"
8
9 // Properties provides access to BiDi properties of runes.
10 type Properties struct {
11         entry uint8
12         last  uint8
13 }
14
15 var trie = newBidiTrie(0)
16
17 // TODO: using this for bidirule reduces the running time by about 5%. Consider
18 // if this is worth exposing or if we can find a way to speed up the Class
19 // method.
20 //
21 // // CompactClass is like Class, but maps all of the BiDi control classes
22 // // (LRO, RLO, LRE, RLE, PDF, LRI, RLI, FSI, PDI) to the class Control.
23 // func (p Properties) CompactClass() Class {
24 //      return Class(p.entry & 0x0F)
25 // }
26
27 // Class returns the Bidi class for p.
28 func (p Properties) Class() Class {
29         c := Class(p.entry & 0x0F)
30         if c == Control {
31                 c = controlByteToClass[p.last&0xF]
32         }
33         return c
34 }
35
36 // IsBracket reports whether the rune is a bracket.
37 func (p Properties) IsBracket() bool { return p.entry&0xF0 != 0 }
38
39 // IsOpeningBracket reports whether the rune is an opening bracket.
40 // IsBracket must return true.
41 func (p Properties) IsOpeningBracket() bool { return p.entry&openMask != 0 }
42
43 // TODO: find a better API and expose.
44 func (p Properties) reverseBracket(r rune) rune {
45         return xorMasks[p.entry>>xorMaskShift] ^ r
46 }
47
48 var controlByteToClass = [16]Class{
49         0xD: LRO, // U+202D LeftToRightOverride,
50         0xE: RLO, // U+202E RightToLeftOverride,
51         0xA: LRE, // U+202A LeftToRightEmbedding,
52         0xB: RLE, // U+202B RightToLeftEmbedding,
53         0xC: PDF, // U+202C PopDirectionalFormat,
54         0x6: LRI, // U+2066 LeftToRightIsolate,
55         0x7: RLI, // U+2067 RightToLeftIsolate,
56         0x8: FSI, // U+2068 FirstStrongIsolate,
57         0x9: PDI, // U+2069 PopDirectionalIsolate,
58 }
59
60 // LookupRune returns properties for r.
61 func LookupRune(r rune) (p Properties, size int) {
62         var buf [4]byte
63         n := utf8.EncodeRune(buf[:], r)
64         return Lookup(buf[:n])
65 }
66
67 // TODO: these lookup methods are based on the generated trie code. The returned
68 // sizes have slightly different semantics from the generated code, in that it
69 // always returns size==1 for an illegal UTF-8 byte (instead of the length
70 // of the maximum invalid subsequence). Most Transformers, like unicode/norm,
71 // leave invalid UTF-8 untouched, in which case it has performance benefits to
72 // do so (without changing the semantics). Bidi requires the semantics used here
73 // for the bidirule implementation to be compatible with the Go semantics.
74 //  They ultimately should perhaps be adopted by all trie implementations, for
75 // convenience sake.
76 // This unrolled code also boosts performance of the secure/bidirule package by
77 // about 30%.
78 // So, to remove this code:
79 //   - add option to trie generator to define return type.
80 //   - always return 1 byte size for ill-formed UTF-8 runes.
81
82 // Lookup returns properties for the first rune in s and the width in bytes of
83 // its encoding. The size will be 0 if s does not hold enough bytes to complete
84 // the encoding.
85 func Lookup(s []byte) (p Properties, sz int) {
86         c0 := s[0]
87         switch {
88         case c0 < 0x80: // is ASCII
89                 return Properties{entry: bidiValues[c0]}, 1
90         case c0 < 0xC2:
91                 return Properties{}, 1
92         case c0 < 0xE0: // 2-byte UTF-8
93                 if len(s) < 2 {
94                         return Properties{}, 0
95                 }
96                 i := bidiIndex[c0]
97                 c1 := s[1]
98                 if c1 < 0x80 || 0xC0 <= c1 {
99                         return Properties{}, 1
100                 }
101                 return Properties{entry: trie.lookupValue(uint32(i), c1)}, 2
102         case c0 < 0xF0: // 3-byte UTF-8
103                 if len(s) < 3 {
104                         return Properties{}, 0
105                 }
106                 i := bidiIndex[c0]
107                 c1 := s[1]
108                 if c1 < 0x80 || 0xC0 <= c1 {
109                         return Properties{}, 1
110                 }
111                 o := uint32(i)<<6 + uint32(c1)
112                 i = bidiIndex[o]
113                 c2 := s[2]
114                 if c2 < 0x80 || 0xC0 <= c2 {
115                         return Properties{}, 1
116                 }
117                 return Properties{entry: trie.lookupValue(uint32(i), c2), last: c2}, 3
118         case c0 < 0xF8: // 4-byte UTF-8
119                 if len(s) < 4 {
120                         return Properties{}, 0
121                 }
122                 i := bidiIndex[c0]
123                 c1 := s[1]
124                 if c1 < 0x80 || 0xC0 <= c1 {
125                         return Properties{}, 1
126                 }
127                 o := uint32(i)<<6 + uint32(c1)
128                 i = bidiIndex[o]
129                 c2 := s[2]
130                 if c2 < 0x80 || 0xC0 <= c2 {
131                         return Properties{}, 1
132                 }
133                 o = uint32(i)<<6 + uint32(c2)
134                 i = bidiIndex[o]
135                 c3 := s[3]
136                 if c3 < 0x80 || 0xC0 <= c3 {
137                         return Properties{}, 1
138                 }
139                 return Properties{entry: trie.lookupValue(uint32(i), c3)}, 4
140         }
141         // Illegal rune
142         return Properties{}, 1
143 }
144
145 // LookupString returns properties for the first rune in s and the width in
146 // bytes of its encoding. The size will be 0 if s does not hold enough bytes to
147 // complete the encoding.
148 func LookupString(s string) (p Properties, sz int) {
149         c0 := s[0]
150         switch {
151         case c0 < 0x80: // is ASCII
152                 return Properties{entry: bidiValues[c0]}, 1
153         case c0 < 0xC2:
154                 return Properties{}, 1
155         case c0 < 0xE0: // 2-byte UTF-8
156                 if len(s) < 2 {
157                         return Properties{}, 0
158                 }
159                 i := bidiIndex[c0]
160                 c1 := s[1]
161                 if c1 < 0x80 || 0xC0 <= c1 {
162                         return Properties{}, 1
163                 }
164                 return Properties{entry: trie.lookupValue(uint32(i), c1)}, 2
165         case c0 < 0xF0: // 3-byte UTF-8
166                 if len(s) < 3 {
167                         return Properties{}, 0
168                 }
169                 i := bidiIndex[c0]
170                 c1 := s[1]
171                 if c1 < 0x80 || 0xC0 <= c1 {
172                         return Properties{}, 1
173                 }
174                 o := uint32(i)<<6 + uint32(c1)
175                 i = bidiIndex[o]
176                 c2 := s[2]
177                 if c2 < 0x80 || 0xC0 <= c2 {
178                         return Properties{}, 1
179                 }
180                 return Properties{entry: trie.lookupValue(uint32(i), c2), last: c2}, 3
181         case c0 < 0xF8: // 4-byte UTF-8
182                 if len(s) < 4 {
183                         return Properties{}, 0
184                 }
185                 i := bidiIndex[c0]
186                 c1 := s[1]
187                 if c1 < 0x80 || 0xC0 <= c1 {
188                         return Properties{}, 1
189                 }
190                 o := uint32(i)<<6 + uint32(c1)
191                 i = bidiIndex[o]
192                 c2 := s[2]
193                 if c2 < 0x80 || 0xC0 <= c2 {
194                         return Properties{}, 1
195                 }
196                 o = uint32(i)<<6 + uint32(c2)
197                 i = bidiIndex[o]
198                 c3 := s[3]
199                 if c3 < 0x80 || 0xC0 <= c3 {
200                         return Properties{}, 1
201                 }
202                 return Properties{entry: trie.lookupValue(uint32(i), c3)}, 4
203         }
204         // Illegal rune
205         return Properties{}, 1
206 }