-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathquote.go
More file actions
121 lines (102 loc) · 3.61 KB
/
quote.go
File metadata and controls
121 lines (102 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package jsonlite
import (
"math/bits"
"unsafe"
)
// Quote returns s as a JSON quoted string.
func Quote(s string) string {
return string(AppendQuote(make([]byte, 0, 2+len(s)), s))
}
// AppendQuote appends a JSON quoted string to b and returns the result.
func AppendQuote(b []byte, s string) []byte {
b = append(b, '"')
for {
i := escapeIndex(s)
if i < 0 {
b = append(b, s...)
break
}
b = append(b, s[:i]...)
switch c := s[i]; c {
case '\\', '"':
b = append(b, '\\', c)
case '\b':
b = append(b, '\\', 'b')
case '\f':
b = append(b, '\\', 'f')
case '\n':
b = append(b, '\\', 'n')
case '\r':
b = append(b, '\\', 'r')
case '\t':
b = append(b, '\\', 't')
default:
const hex = "0123456789abcdef"
b = append(b, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xf])
}
s = s[i+1:]
}
return append(b, '"')
}
/*
MIT License
Copyright (c) 2019 Segment.io, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
const (
lsb = 0x0101010101010101
msb = 0x8080808080808080
)
// escapeIndex finds the index of the first char in `s` that requires escaping.
// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if
// it includes a double quote or backslash. If no chars in `s` require escaping,
// the return value is -1.
func escapeIndex(s string) int {
var i int
if len(s) >= 8 {
chunks := unsafe.Slice((*uint64)(unsafe.Pointer(unsafe.StringData(s))), len(s)/8)
for j, n := range chunks {
// combine masks before checking for the MSB of each byte. We include
// `n` in the mask to check whether any of the *input* byte MSBs were
// set (i.e. the byte was outside the ASCII range).
mask := n | below(n, 0x20) | contains(n, '"') | contains(n, '\\')
if (mask & msb) != 0 {
return j*8 + bits.TrailingZeros64(mask&msb)/8
}
}
i = len(chunks) * 8
}
for ; i < len(s); i++ {
c := s[i]
if c < 0x20 || c > 0x7f || c == '"' || c == '\\' {
return i
}
}
return -1
}
// below return a mask that can be used to determine if any of the bytes
// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was
// below `b`. The result is only valid if `b`, and each byte in `n`, is below
// 0x80.
func below(n uint64, b byte) uint64 { return n - expand(b) }
// contains returns a mask that can be used to determine if any of the
// bytes in `n` are equal to `b`. If a byte's MSB is set in the mask then
// that byte is equal to `b`. The result is only valid if `b`, and each
// byte in `n`, is below 0x80.
func contains(n uint64, b byte) uint64 { return (n ^ expand(b)) - lsb }
// expand puts the specified byte into each of the 8 bytes of a uint64.
func expand(b byte) uint64 { return lsb * uint64(b) }