Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/golang.org/x/text/cases/context.go
2880 views
1
// Copyright 2014 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 cases
6
7
import "golang.org/x/text/transform"
8
9
// A context is used for iterating over source bytes, fetching case info and
10
// writing to a destination buffer.
11
//
12
// Casing operations may need more than one rune of context to decide how a rune
13
// should be cased. Casing implementations should call checkpoint on context
14
// whenever it is known to be safe to return the runes processed so far.
15
//
16
// It is recommended for implementations to not allow for more than 30 case
17
// ignorables as lookahead (analogous to the limit in norm) and to use state if
18
// unbounded lookahead is needed for cased runes.
19
type context struct {
20
dst, src []byte
21
atEOF bool
22
23
pDst int // pDst points past the last written rune in dst.
24
pSrc int // pSrc points to the start of the currently scanned rune.
25
26
// checkpoints safe to return in Transform, where nDst <= pDst and nSrc <= pSrc.
27
nDst, nSrc int
28
err error
29
30
sz int // size of current rune
31
info info // case information of currently scanned rune
32
33
// State preserved across calls to Transform.
34
isMidWord bool // false if next cased letter needs to be title-cased.
35
}
36
37
func (c *context) Reset() {
38
c.isMidWord = false
39
}
40
41
// ret returns the return values for the Transform method. It checks whether
42
// there were insufficient bytes in src to complete and introduces an error
43
// accordingly, if necessary.
44
func (c *context) ret() (nDst, nSrc int, err error) {
45
if c.err != nil || c.nSrc == len(c.src) {
46
return c.nDst, c.nSrc, c.err
47
}
48
// This point is only reached by mappers if there was no short destination
49
// buffer. This means that the source buffer was exhausted and that c.sz was
50
// set to 0 by next.
51
if c.atEOF && c.pSrc == len(c.src) {
52
return c.pDst, c.pSrc, nil
53
}
54
return c.nDst, c.nSrc, transform.ErrShortSrc
55
}
56
57
// retSpan returns the return values for the Span method. It checks whether
58
// there were insufficient bytes in src to complete and introduces an error
59
// accordingly, if necessary.
60
func (c *context) retSpan() (n int, err error) {
61
_, nSrc, err := c.ret()
62
return nSrc, err
63
}
64
65
// checkpoint sets the return value buffer points for Transform to the current
66
// positions.
67
func (c *context) checkpoint() {
68
if c.err == nil {
69
c.nDst, c.nSrc = c.pDst, c.pSrc+c.sz
70
}
71
}
72
73
// unreadRune causes the last rune read by next to be reread on the next
74
// invocation of next. Only one unreadRune may be called after a call to next.
75
func (c *context) unreadRune() {
76
c.sz = 0
77
}
78
79
func (c *context) next() bool {
80
c.pSrc += c.sz
81
if c.pSrc == len(c.src) || c.err != nil {
82
c.info, c.sz = 0, 0
83
return false
84
}
85
v, sz := trie.lookup(c.src[c.pSrc:])
86
c.info, c.sz = info(v), sz
87
if c.sz == 0 {
88
if c.atEOF {
89
// A zero size means we have an incomplete rune. If we are atEOF,
90
// this means it is an illegal rune, which we will consume one
91
// byte at a time.
92
c.sz = 1
93
} else {
94
c.err = transform.ErrShortSrc
95
return false
96
}
97
}
98
return true
99
}
100
101
// writeBytes adds bytes to dst.
102
func (c *context) writeBytes(b []byte) bool {
103
if len(c.dst)-c.pDst < len(b) {
104
c.err = transform.ErrShortDst
105
return false
106
}
107
// This loop is faster than using copy.
108
for _, ch := range b {
109
c.dst[c.pDst] = ch
110
c.pDst++
111
}
112
return true
113
}
114
115
// writeString writes the given string to dst.
116
func (c *context) writeString(s string) bool {
117
if len(c.dst)-c.pDst < len(s) {
118
c.err = transform.ErrShortDst
119
return false
120
}
121
// This loop is faster than using copy.
122
for i := 0; i < len(s); i++ {
123
c.dst[c.pDst] = s[i]
124
c.pDst++
125
}
126
return true
127
}
128
129
// copy writes the current rune to dst.
130
func (c *context) copy() bool {
131
return c.writeBytes(c.src[c.pSrc : c.pSrc+c.sz])
132
}
133
134
// copyXOR copies the current rune to dst and modifies it by applying the XOR
135
// pattern of the case info. It is the responsibility of the caller to ensure
136
// that this is a rune with a XOR pattern defined.
137
func (c *context) copyXOR() bool {
138
if !c.copy() {
139
return false
140
}
141
if c.info&xorIndexBit == 0 {
142
// Fast path for 6-bit XOR pattern, which covers most cases.
143
c.dst[c.pDst-1] ^= byte(c.info >> xorShift)
144
} else {
145
// Interpret XOR bits as an index.
146
// TODO: test performance for unrolling this loop. Verify that we have
147
// at least two bytes and at most three.
148
idx := c.info >> xorShift
149
for p := c.pDst - 1; ; p-- {
150
c.dst[p] ^= xorData[idx]
151
idx--
152
if xorData[idx] == 0 {
153
break
154
}
155
}
156
}
157
return true
158
}
159
160
// hasPrefix returns true if src[pSrc:] starts with the given string.
161
func (c *context) hasPrefix(s string) bool {
162
b := c.src[c.pSrc:]
163
if len(b) < len(s) {
164
return false
165
}
166
for i, c := range b[:len(s)] {
167
if c != s[i] {
168
return false
169
}
170
}
171
return true
172
}
173
174
// caseType returns an info with only the case bits, normalized to either
175
// cLower, cUpper, cTitle or cUncased.
176
func (c *context) caseType() info {
177
cm := c.info & 0x7
178
if cm < 4 {
179
return cm
180
}
181
if cm >= cXORCase {
182
// xor the last bit of the rune with the case type bits.
183
b := c.src[c.pSrc+c.sz-1]
184
return info(b&1) ^ cm&0x3
185
}
186
if cm == cIgnorableCased {
187
return cLower
188
}
189
return cUncased
190
}
191
192
// lower writes the lowercase version of the current rune to dst.
193
func lower(c *context) bool {
194
ct := c.caseType()
195
if c.info&hasMappingMask == 0 || ct == cLower {
196
return c.copy()
197
}
198
if c.info&exceptionBit == 0 {
199
return c.copyXOR()
200
}
201
e := exceptions[c.info>>exceptionShift:]
202
offset := 2 + e[0]&lengthMask // size of header + fold string
203
if nLower := (e[1] >> lengthBits) & lengthMask; nLower != noChange {
204
return c.writeString(e[offset : offset+nLower])
205
}
206
return c.copy()
207
}
208
209
func isLower(c *context) bool {
210
ct := c.caseType()
211
if c.info&hasMappingMask == 0 || ct == cLower {
212
return true
213
}
214
if c.info&exceptionBit == 0 {
215
c.err = transform.ErrEndOfSpan
216
return false
217
}
218
e := exceptions[c.info>>exceptionShift:]
219
if nLower := (e[1] >> lengthBits) & lengthMask; nLower != noChange {
220
c.err = transform.ErrEndOfSpan
221
return false
222
}
223
return true
224
}
225
226
// upper writes the uppercase version of the current rune to dst.
227
func upper(c *context) bool {
228
ct := c.caseType()
229
if c.info&hasMappingMask == 0 || ct == cUpper {
230
return c.copy()
231
}
232
if c.info&exceptionBit == 0 {
233
return c.copyXOR()
234
}
235
e := exceptions[c.info>>exceptionShift:]
236
offset := 2 + e[0]&lengthMask // size of header + fold string
237
// Get length of first special case mapping.
238
n := (e[1] >> lengthBits) & lengthMask
239
if ct == cTitle {
240
// The first special case mapping is for lower. Set n to the second.
241
if n == noChange {
242
n = 0
243
}
244
n, e = e[1]&lengthMask, e[n:]
245
}
246
if n != noChange {
247
return c.writeString(e[offset : offset+n])
248
}
249
return c.copy()
250
}
251
252
// isUpper writes the isUppercase version of the current rune to dst.
253
func isUpper(c *context) bool {
254
ct := c.caseType()
255
if c.info&hasMappingMask == 0 || ct == cUpper {
256
return true
257
}
258
if c.info&exceptionBit == 0 {
259
c.err = transform.ErrEndOfSpan
260
return false
261
}
262
e := exceptions[c.info>>exceptionShift:]
263
// Get length of first special case mapping.
264
n := (e[1] >> lengthBits) & lengthMask
265
if ct == cTitle {
266
n = e[1] & lengthMask
267
}
268
if n != noChange {
269
c.err = transform.ErrEndOfSpan
270
return false
271
}
272
return true
273
}
274
275
// title writes the title case version of the current rune to dst.
276
func title(c *context) bool {
277
ct := c.caseType()
278
if c.info&hasMappingMask == 0 || ct == cTitle {
279
return c.copy()
280
}
281
if c.info&exceptionBit == 0 {
282
if ct == cLower {
283
return c.copyXOR()
284
}
285
return c.copy()
286
}
287
// Get the exception data.
288
e := exceptions[c.info>>exceptionShift:]
289
offset := 2 + e[0]&lengthMask // size of header + fold string
290
291
nFirst := (e[1] >> lengthBits) & lengthMask
292
if nTitle := e[1] & lengthMask; nTitle != noChange {
293
if nFirst != noChange {
294
e = e[nFirst:]
295
}
296
return c.writeString(e[offset : offset+nTitle])
297
}
298
if ct == cLower && nFirst != noChange {
299
// Use the uppercase version instead.
300
return c.writeString(e[offset : offset+nFirst])
301
}
302
// Already in correct case.
303
return c.copy()
304
}
305
306
// isTitle reports whether the current rune is in title case.
307
func isTitle(c *context) bool {
308
ct := c.caseType()
309
if c.info&hasMappingMask == 0 || ct == cTitle {
310
return true
311
}
312
if c.info&exceptionBit == 0 {
313
if ct == cLower {
314
c.err = transform.ErrEndOfSpan
315
return false
316
}
317
return true
318
}
319
// Get the exception data.
320
e := exceptions[c.info>>exceptionShift:]
321
if nTitle := e[1] & lengthMask; nTitle != noChange {
322
c.err = transform.ErrEndOfSpan
323
return false
324
}
325
nFirst := (e[1] >> lengthBits) & lengthMask
326
if ct == cLower && nFirst != noChange {
327
c.err = transform.ErrEndOfSpan
328
return false
329
}
330
return true
331
}
332
333
// foldFull writes the foldFull version of the current rune to dst.
334
func foldFull(c *context) bool {
335
if c.info&hasMappingMask == 0 {
336
return c.copy()
337
}
338
ct := c.caseType()
339
if c.info&exceptionBit == 0 {
340
if ct != cLower || c.info&inverseFoldBit != 0 {
341
return c.copyXOR()
342
}
343
return c.copy()
344
}
345
e := exceptions[c.info>>exceptionShift:]
346
n := e[0] & lengthMask
347
if n == 0 {
348
if ct == cLower {
349
return c.copy()
350
}
351
n = (e[1] >> lengthBits) & lengthMask
352
}
353
return c.writeString(e[2 : 2+n])
354
}
355
356
// isFoldFull reports whether the current run is mapped to foldFull
357
func isFoldFull(c *context) bool {
358
if c.info&hasMappingMask == 0 {
359
return true
360
}
361
ct := c.caseType()
362
if c.info&exceptionBit == 0 {
363
if ct != cLower || c.info&inverseFoldBit != 0 {
364
c.err = transform.ErrEndOfSpan
365
return false
366
}
367
return true
368
}
369
e := exceptions[c.info>>exceptionShift:]
370
n := e[0] & lengthMask
371
if n == 0 && ct == cLower {
372
return true
373
}
374
c.err = transform.ErrEndOfSpan
375
return false
376
}
377
378