gofront 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/package.json +10 -38
- package/src/backend/js/expressions.js +2060 -389
- package/src/backend/js/index.js +586 -174
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +936 -1644
- package/src/backend/js/statements.js +1349 -132
- package/src/backend/js/stdlib/index.js +51 -94
- package/src/backend/js/templ.js +67 -118
- package/src/backend/js/type-info.js +436 -0
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +80 -0
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +753 -872
- package/src/backend/wasm/emit-builtins.js +914 -237
- package/src/backend/wasm/emit-exprs.js +1456 -195
- package/src/backend/wasm/emit-maps.js +78 -380
- package/src/backend/wasm/emit-stmts.js +1659 -214
- package/src/backend/wasm/emit.js +614 -88
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +491 -0
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +406 -3195
- package/src/backend/wasm/method-expr.js +392 -0
- package/src/backend/wasm/module-emitter.js +1615 -0
- package/src/backend/wasm/monomorph.js +164 -9
- package/src/backend/wasm/natives.js +596 -0
- package/src/backend/wasm/prescan.js +249 -0
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -37
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/types.js +260 -27
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +47 -20
- package/src/{cli-core.js → cli/cli-core.js} +241 -11
- package/src/{test-runner.js → cli/test-runner.js} +188 -122
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +202 -386
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +203 -62
- package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
- package/src/{tokens.js → lexer/tokens.js} +2 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +737 -0
- package/src/link/type-names.js +148 -0
- package/src/link/wasm.js +318 -0
- package/src/lower/bounds.js +547 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +267 -64
- package/src/lower/embedding.js +32 -3
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +905 -0
- package/src/lower/functions.js +2 -0
- package/src/lower/gen-types.js +274 -0
- package/src/lower/index.js +33 -19
- package/src/lower/json-codecs.js +1379 -0
- package/src/lower/ownership.js +47 -8
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +150 -0
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +83 -15
- package/src/parser/expressions.js +110 -18
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +38 -22
- package/src/{templ-parser.js → parser/templ.js} +179 -17
- package/src/parser/types.js +70 -9
- package/src/resolver.js +21 -1
- package/src/typechecker/assignability.js +291 -19
- package/src/typechecker/const-fold.js +399 -0
- package/src/typechecker/constants.js +282 -0
- package/src/typechecker/expressions.js +1220 -183
- package/src/typechecker/index.js +659 -92
- package/src/typechecker/init-order.js +426 -0
- package/src/typechecker/operand-text.js +40 -0
- package/src/typechecker/resolve.js +613 -62
- package/src/typechecker/statements.js +212 -20
- package/src/typechecker/stdlib/excluded.js +902 -0
- package/src/typechecker/stdlib/index.js +38 -0
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +11 -2
- package/src/typechecker/types.js +268 -514
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +871 -0
- package/stdlib/internal/jsonrt/enc.go +516 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +658 -0
- package/stdlib/io/io.go +502 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +272 -0
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +500 -0
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +526 -0
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +250 -0
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -46
- package/src/backend/js/stdlib/builder.js +0 -63
- package/src/backend/js/stdlib/bytes.js +0 -122
- package/src/backend/js/stdlib/errors.js +0 -44
- package/src/backend/js/stdlib/fmt.js +0 -178
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -972
- package/src/backend/js/stdlib/maps.js +0 -45
- package/src/backend/js/stdlib/math.js +0 -69
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -24
- package/src/backend/js/stdlib/slices.js +0 -77
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -74
- package/src/backend/js/stdlib/strings.js +0 -222
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -34
- package/src/backend/js/stdlib/time.js +0 -128
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- package/src/backend/wasm/stdlib/bytes.js +0 -5039
- package/src/backend/wasm/stdlib/core.js +0 -8903
- package/src/backend/wasm/stdlib/io.js +0 -2161
- package/src/backend/wasm/stdlib/packages.js +0 -2400
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -1200
- package/src/typechecker/stdlib/core.js +0 -801
- package/src/typechecker/stdlib/extended.js +0 -914
- package/src/typechecker/stdlib.js +0 -22
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
|
@@ -0,0 +1,1010 @@
|
|
|
1
|
+
//go:build gofront
|
|
2
|
+
|
|
3
|
+
//gofront:target both
|
|
4
|
+
|
|
5
|
+
// Package bytes implements functions for the manipulation of byte slices,
|
|
6
|
+
// written in Go over the real package's algorithms. Offsets are byte
|
|
7
|
+
// offsets and UTF-8 is decoded as Go does, so an invalid sequence reads as
|
|
8
|
+
// (RuneError, 1). Like Go's, the slices that the split and sequence
|
|
9
|
+
// functions return alias the input and have their capacity clipped.
|
|
10
|
+
package bytes
|
|
11
|
+
|
|
12
|
+
import (
|
|
13
|
+
"iter"
|
|
14
|
+
"unicode"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
const (
|
|
18
|
+
runeError = 0xFFFD
|
|
19
|
+
runeSelf = 0x80
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
// decodeRune unpacks the first UTF-8 encoding in p and returns the rune and
|
|
23
|
+
// its width in bytes, as utf8.DecodeRune does: an invalid or incomplete
|
|
24
|
+
// encoding is (RuneError, 1) and p must not be empty.
|
|
25
|
+
func decodeRune(p []byte) (rune, int) {
|
|
26
|
+
b0 := int(p[0])
|
|
27
|
+
if b0 < runeSelf {
|
|
28
|
+
return rune(b0), 1
|
|
29
|
+
}
|
|
30
|
+
n, lo, mask := 0, 0, 0
|
|
31
|
+
if b0 >= 0xC2 && b0 <= 0xDF {
|
|
32
|
+
n, lo, mask = 2, 0x80, 0x1F
|
|
33
|
+
} else if b0 >= 0xE0 && b0 <= 0xEF {
|
|
34
|
+
n, lo, mask = 3, 0x800, 0x0F
|
|
35
|
+
} else if b0 >= 0xF0 && b0 <= 0xF4 {
|
|
36
|
+
n, lo, mask = 4, 0x10000, 0x07
|
|
37
|
+
} else {
|
|
38
|
+
return runeError, 1
|
|
39
|
+
}
|
|
40
|
+
if len(p) < n {
|
|
41
|
+
return runeError, 1
|
|
42
|
+
}
|
|
43
|
+
r := b0 & mask
|
|
44
|
+
for i := 1; i < n; i++ {
|
|
45
|
+
b := int(p[i])
|
|
46
|
+
if b&0xC0 != 0x80 {
|
|
47
|
+
return runeError, 1
|
|
48
|
+
}
|
|
49
|
+
r = r<<6 | b&0x3F
|
|
50
|
+
}
|
|
51
|
+
if r < lo || r > 0x10FFFF || (r >= 0xD800 && r <= 0xDFFF) {
|
|
52
|
+
return runeError, 1
|
|
53
|
+
}
|
|
54
|
+
return rune(r), n
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// isSpace is unicode.IsSpace as a func(rune) bool.
|
|
58
|
+
func isSpace(r rune) bool {
|
|
59
|
+
return unicode.IsSpace(r)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Lines returns an iterator over the newline-terminated lines in the byte slice s.
|
|
63
|
+
// The lines yielded by the iterator include their terminating newlines.
|
|
64
|
+
// If s is empty, the iterator yields no lines at all.
|
|
65
|
+
// If s does not end in a newline, the final yielded line will not end in a newline.
|
|
66
|
+
// The iterator yields slices of the original slice s.
|
|
67
|
+
func Lines(s []byte) iter.Seq[[]byte] {
|
|
68
|
+
return func(yield func([]byte) bool) {
|
|
69
|
+
for len(s) > 0 {
|
|
70
|
+
var line []byte
|
|
71
|
+
if i := IndexByte(s, '\n'); i >= 0 {
|
|
72
|
+
line, s = s[:i+1:i+1], s[i+1:]
|
|
73
|
+
} else {
|
|
74
|
+
line, s = s[:len(s):len(s)], nil
|
|
75
|
+
}
|
|
76
|
+
if !yield(line) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// explodeSeq returns an iterator over the UTF-8 encodings of the runes in s.
|
|
84
|
+
func explodeSeq(s []byte) iter.Seq[[]byte] {
|
|
85
|
+
return func(yield func([]byte) bool) {
|
|
86
|
+
for len(s) > 0 {
|
|
87
|
+
_, size := decodeRune(s)
|
|
88
|
+
if !yield(s[:size:size]) {
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
s = s[size:]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// splitSeq is SplitSeq or SplitAfterSeq, configured by how many
|
|
97
|
+
// bytes of sep to include in the results (none or all).
|
|
98
|
+
func splitSeq(s, sep []byte, sepSave int) iter.Seq[[]byte] {
|
|
99
|
+
if len(sep) == 0 {
|
|
100
|
+
return explodeSeq(s)
|
|
101
|
+
}
|
|
102
|
+
return func(yield func([]byte) bool) {
|
|
103
|
+
for {
|
|
104
|
+
i := Index(s, sep)
|
|
105
|
+
if i < 0 {
|
|
106
|
+
break
|
|
107
|
+
}
|
|
108
|
+
frag := s[:i+sepSave]
|
|
109
|
+
if !yield(frag[:len(frag):len(frag)]) {
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
s = s[i+len(sep):]
|
|
113
|
+
}
|
|
114
|
+
yield(s[:len(s):len(s)])
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// SplitSeq returns an iterator over subslices of s split around sep.
|
|
119
|
+
// The iterator yields the same subslices that would be returned by Split(s, sep),
|
|
120
|
+
// but without constructing the slice.
|
|
121
|
+
// It returns a single-use iterator.
|
|
122
|
+
func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
|
|
123
|
+
return splitSeq(s, sep, 0)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// SplitAfterSeq returns an iterator over subslices of s split after each instance of sep.
|
|
127
|
+
// The iterator yields the same subslices that would be returned by SplitAfter(s, sep),
|
|
128
|
+
// but without constructing the slice.
|
|
129
|
+
// It returns a single-use iterator.
|
|
130
|
+
func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
|
|
131
|
+
return splitSeq(s, sep, len(sep))
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// FieldsSeq returns an iterator over subslices of s split around runs of
|
|
135
|
+
// whitespace characters, as defined by unicode.IsSpace.
|
|
136
|
+
// The iterator yields the same subslices that would be returned by Fields(s),
|
|
137
|
+
// but without constructing the slice.
|
|
138
|
+
func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
|
139
|
+
return FieldsFuncSeq(s, isSpace)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// FieldsFuncSeq returns an iterator over subslices of s split around runs of
|
|
143
|
+
// Unicode code points satisfying f(c).
|
|
144
|
+
// The iterator yields the same subslices that would be returned by FieldsFunc(s),
|
|
145
|
+
// but without constructing the slice.
|
|
146
|
+
func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
|
|
147
|
+
return func(yield func([]byte) bool) {
|
|
148
|
+
start := -1
|
|
149
|
+
for i := 0; i < len(s); {
|
|
150
|
+
size := 1
|
|
151
|
+
r := rune(s[i])
|
|
152
|
+
if r >= runeSelf {
|
|
153
|
+
r, size = decodeRune(s[i:])
|
|
154
|
+
}
|
|
155
|
+
if f(r) {
|
|
156
|
+
if start >= 0 {
|
|
157
|
+
if !yield(s[start:i:i]) {
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
start = -1
|
|
161
|
+
}
|
|
162
|
+
} else if start < 0 {
|
|
163
|
+
start = i
|
|
164
|
+
}
|
|
165
|
+
i += size
|
|
166
|
+
}
|
|
167
|
+
if start >= 0 {
|
|
168
|
+
yield(s[start:len(s):len(s)])
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
// IndexByte returns the index of the first instance of c in b, or -1 if c is
|
|
175
|
+
// not present in b.
|
|
176
|
+
//
|
|
177
|
+
//gofront:native bytes.IndexByte
|
|
178
|
+
func IndexByte(b []byte, c byte) int {
|
|
179
|
+
for i, x := range b {
|
|
180
|
+
if x == c {
|
|
181
|
+
return i
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return -1
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Equal reports whether a and b are the same length and contain the same
|
|
188
|
+
// bytes. A nil argument is equivalent to an empty slice.
|
|
189
|
+
//
|
|
190
|
+
//gofront:native bytes.Equal
|
|
191
|
+
func Equal(a, b []byte) bool {
|
|
192
|
+
if len(a) != len(b) {
|
|
193
|
+
return false
|
|
194
|
+
}
|
|
195
|
+
for i := range a {
|
|
196
|
+
if a[i] != b[i] {
|
|
197
|
+
return false
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return true
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Index returns the index of the first instance of sep in s, or -1 if sep is
|
|
204
|
+
// not present in s.
|
|
205
|
+
func Index(s, sep []byte) int {
|
|
206
|
+
n := len(sep)
|
|
207
|
+
switch {
|
|
208
|
+
case n == 0:
|
|
209
|
+
return 0
|
|
210
|
+
case n == 1:
|
|
211
|
+
return IndexByte(s, sep[0])
|
|
212
|
+
case n == len(s):
|
|
213
|
+
if Equal(sep, s) {
|
|
214
|
+
return 0
|
|
215
|
+
}
|
|
216
|
+
return -1
|
|
217
|
+
case n > len(s):
|
|
218
|
+
return -1
|
|
219
|
+
}
|
|
220
|
+
c0 := sep[0]
|
|
221
|
+
for i := 0; i+n <= len(s); i++ {
|
|
222
|
+
j := IndexByte(s[i:len(s)-n+1], c0)
|
|
223
|
+
if j < 0 {
|
|
224
|
+
return -1
|
|
225
|
+
}
|
|
226
|
+
i += j
|
|
227
|
+
if Equal(s[i:i+n], sep) {
|
|
228
|
+
return i
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return -1
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// LastIndex returns the index of the last instance of sep in s, or -1 if sep
|
|
235
|
+
// is not present in s.
|
|
236
|
+
func LastIndex(s, sep []byte) int {
|
|
237
|
+
n := len(sep)
|
|
238
|
+
if n == 0 {
|
|
239
|
+
return len(s)
|
|
240
|
+
}
|
|
241
|
+
for i := len(s) - n; i >= 0; i-- {
|
|
242
|
+
if s[i] == sep[0] && Equal(s[i:i+n], sep) {
|
|
243
|
+
return i
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return -1
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// LastIndexByte returns the index of the last instance of c in s, or -1 if c
|
|
250
|
+
// is not present in s.
|
|
251
|
+
func LastIndexByte(s []byte, c byte) int {
|
|
252
|
+
for i := len(s) - 1; i >= 0; i-- {
|
|
253
|
+
if s[i] == c {
|
|
254
|
+
return i
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return -1
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Contains reports whether subslice is within b.
|
|
261
|
+
func Contains(b, subslice []byte) bool {
|
|
262
|
+
return Index(b, subslice) != -1
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ContainsAny reports whether any of the UTF-8-encoded code points in chars
|
|
266
|
+
// are within b.
|
|
267
|
+
func ContainsAny(b []byte, chars string) bool {
|
|
268
|
+
return IndexAny(b, chars) >= 0
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ContainsRune reports whether the rune is contained in the UTF-8-encoded
|
|
272
|
+
// byte slice b.
|
|
273
|
+
func ContainsRune(b []byte, r rune) bool {
|
|
274
|
+
return IndexRune(b, r) >= 0
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Count counts the number of non-overlapping instances of sep in s.
|
|
278
|
+
// If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded
|
|
279
|
+
// code points in s.
|
|
280
|
+
func Count(s, sep []byte) int {
|
|
281
|
+
if len(sep) == 0 {
|
|
282
|
+
return runeCount(s) + 1
|
|
283
|
+
}
|
|
284
|
+
return countSep(s, sep)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// HasPrefix reports whether the byte slice s begins with prefix.
|
|
288
|
+
func HasPrefix(s, prefix []byte) bool {
|
|
289
|
+
return len(s) >= len(prefix) && Equal(s[:len(prefix)], prefix)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// HasSuffix reports whether the byte slice s ends with suffix.
|
|
293
|
+
func HasSuffix(s, suffix []byte) bool {
|
|
294
|
+
return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):], suffix)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Clone returns a copy of b[:len(b)].
|
|
298
|
+
// The result may have additional unused capacity.
|
|
299
|
+
// Clone(nil) returns nil.
|
|
300
|
+
func Clone(b []byte) []byte {
|
|
301
|
+
if b == nil {
|
|
302
|
+
return nil
|
|
303
|
+
}
|
|
304
|
+
return append([]byte{}, b...)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Cut slices s around the first instance of sep,
|
|
308
|
+
// returning the text before and after sep.
|
|
309
|
+
// The found result reports whether sep appears in s.
|
|
310
|
+
// If sep does not appear in s, cut returns s, nil, false.
|
|
311
|
+
func Cut(s, sep []byte) (before, after []byte, found bool) {
|
|
312
|
+
if i := Index(s, sep); i >= 0 {
|
|
313
|
+
return s[:i], s[i+len(sep):], true
|
|
314
|
+
}
|
|
315
|
+
return s, nil, false
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Repeat returns a new byte slice consisting of count copies of b.
|
|
319
|
+
// It panics if count is negative.
|
|
320
|
+
func Repeat(b []byte, count int) []byte {
|
|
321
|
+
if count < 0 {
|
|
322
|
+
panic("bytes: negative Repeat count")
|
|
323
|
+
}
|
|
324
|
+
nb := make([]byte, 0, len(b)*count)
|
|
325
|
+
for i := 0; i < count; i++ {
|
|
326
|
+
nb = append(nb, b...)
|
|
327
|
+
}
|
|
328
|
+
return nb
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Split slices s into all subslices separated by sep and returns a slice of
|
|
332
|
+
// the subslices between those separators.
|
|
333
|
+
// If sep is empty, Split splits after each UTF-8 sequence.
|
|
334
|
+
// It is equivalent to SplitN with a count of -1.
|
|
335
|
+
func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) }
|
|
336
|
+
|
|
337
|
+
// SplitN slices s into subslices separated by sep and returns a slice of
|
|
338
|
+
// the subslices between those separators.
|
|
339
|
+
// The count determines the number of subslices to return:
|
|
340
|
+
// - n > 0: at most n subslices; the last subslice will be the unsplit remainder;
|
|
341
|
+
// - n == 0: the result is nil (zero subslices);
|
|
342
|
+
// - n < 0: all subslices.
|
|
343
|
+
func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
|
|
344
|
+
|
|
345
|
+
// Join concatenates the elements of s to create a new byte slice. The separator
|
|
346
|
+
// sep is placed between elements in the resulting slice.
|
|
347
|
+
func Join(s [][]byte, sep []byte) []byte {
|
|
348
|
+
if len(s) == 0 {
|
|
349
|
+
return []byte{}
|
|
350
|
+
}
|
|
351
|
+
if len(s) == 1 {
|
|
352
|
+
return append([]byte(nil), s[0]...)
|
|
353
|
+
}
|
|
354
|
+
n := len(sep) * (len(s) - 1)
|
|
355
|
+
for _, v := range s {
|
|
356
|
+
n += len(v)
|
|
357
|
+
}
|
|
358
|
+
b := make([]byte, 0, n)
|
|
359
|
+
b = append(b, s[0]...)
|
|
360
|
+
for _, v := range s[1:] {
|
|
361
|
+
b = append(b, sep...)
|
|
362
|
+
b = append(b, v...)
|
|
363
|
+
}
|
|
364
|
+
return b
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// span is the byte range of one field.
|
|
368
|
+
type span struct {
|
|
369
|
+
start int
|
|
370
|
+
end int
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// FieldsFunc interprets s as a sequence of UTF-8-encoded code points.
|
|
374
|
+
// It splits the slice s at each run of code points c satisfying f(c) and
|
|
375
|
+
// returns a slice of subslices of s. If all code points in s satisfy f(c), or
|
|
376
|
+
// len(s) == 0, an empty slice is returned.
|
|
377
|
+
func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
|
|
378
|
+
spans := make([]span, 0, 32)
|
|
379
|
+
start := -1
|
|
380
|
+
for i := 0; i < len(s); {
|
|
381
|
+
size := 1
|
|
382
|
+
r := rune(s[i])
|
|
383
|
+
if r >= runeSelf {
|
|
384
|
+
r, size = decodeRune(s[i:])
|
|
385
|
+
}
|
|
386
|
+
if f(r) {
|
|
387
|
+
if start >= 0 {
|
|
388
|
+
spans = append(spans, span{start, i})
|
|
389
|
+
start = -1
|
|
390
|
+
}
|
|
391
|
+
} else if start < 0 {
|
|
392
|
+
start = i
|
|
393
|
+
}
|
|
394
|
+
i += size
|
|
395
|
+
}
|
|
396
|
+
if start >= 0 {
|
|
397
|
+
spans = append(spans, span{start, len(s)})
|
|
398
|
+
}
|
|
399
|
+
a := make([][]byte, len(spans))
|
|
400
|
+
for i, sp := range spans {
|
|
401
|
+
a[i] = s[sp.start:sp.end:sp.end]
|
|
402
|
+
}
|
|
403
|
+
return a
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Fields interprets s as a sequence of UTF-8-encoded code points.
|
|
407
|
+
// It splits the slice s around each instance of one or more consecutive white
|
|
408
|
+
// space characters, as defined by unicode.IsSpace, returning a slice of
|
|
409
|
+
// subslices of s or an empty slice if s contains only white space.
|
|
410
|
+
func Fields(s []byte) [][]byte { return FieldsFunc(s, isSpace) }
|
|
411
|
+
|
|
412
|
+
// Map returns a copy of the byte slice s with all its characters modified
|
|
413
|
+
// according to the mapping function. If mapping returns a negative value, the
|
|
414
|
+
// character is dropped from the byte slice with no replacement. The characters
|
|
415
|
+
// in s and the output are interpreted as UTF-8-encoded code points.
|
|
416
|
+
func Map(mapping func(r rune) rune, s []byte) []byte {
|
|
417
|
+
b := make([]byte, 0, len(s))
|
|
418
|
+
for i := 0; i < len(s); {
|
|
419
|
+
wid := 1
|
|
420
|
+
r := rune(s[i])
|
|
421
|
+
if r >= runeSelf {
|
|
422
|
+
r, wid = decodeRune(s[i:])
|
|
423
|
+
}
|
|
424
|
+
r = mapping(r)
|
|
425
|
+
if r >= 0 {
|
|
426
|
+
b = appendRune(b, r)
|
|
427
|
+
}
|
|
428
|
+
i += wid
|
|
429
|
+
}
|
|
430
|
+
return b
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
func upperRune(r rune) rune { return unicode.ToUpper(r) }
|
|
434
|
+
func lowerRune(r rune) rune { return unicode.ToLower(r) }
|
|
435
|
+
|
|
436
|
+
// ToUpper returns a copy of s with all Unicode letters mapped to their
|
|
437
|
+
// upper case.
|
|
438
|
+
func ToUpper(s []byte) []byte { return Map(upperRune, s) }
|
|
439
|
+
|
|
440
|
+
// ToLower returns a copy of s with all Unicode letters mapped to their
|
|
441
|
+
// lower case.
|
|
442
|
+
func ToLower(s []byte) []byte { return Map(lowerRune, s) }
|
|
443
|
+
|
|
444
|
+
// ToTitle treats s as UTF-8-encoded bytes and returns a copy with all the
|
|
445
|
+
// Unicode letters mapped to their title case.
|
|
446
|
+
func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) }
|
|
447
|
+
|
|
448
|
+
// ToValidUTF8 treats s as UTF-8-encoded bytes and returns a copy with each
|
|
449
|
+
// run of bytes representing invalid UTF-8 replaced with the bytes in
|
|
450
|
+
// replacement, which may be empty.
|
|
451
|
+
func ToValidUTF8(s, replacement []byte) []byte {
|
|
452
|
+
b := make([]byte, 0, len(s)+len(replacement))
|
|
453
|
+
invalid := false
|
|
454
|
+
for i := 0; i < len(s); {
|
|
455
|
+
c := s[i]
|
|
456
|
+
if c < runeSelf {
|
|
457
|
+
i++
|
|
458
|
+
invalid = false
|
|
459
|
+
b = append(b, c)
|
|
460
|
+
continue
|
|
461
|
+
}
|
|
462
|
+
_, wid := decodeRune(s[i:])
|
|
463
|
+
if wid == 1 {
|
|
464
|
+
i++
|
|
465
|
+
if !invalid {
|
|
466
|
+
invalid = true
|
|
467
|
+
b = append(b, replacement...)
|
|
468
|
+
}
|
|
469
|
+
continue
|
|
470
|
+
}
|
|
471
|
+
invalid = false
|
|
472
|
+
b = append(b, s[i:i+wid]...)
|
|
473
|
+
i += wid
|
|
474
|
+
}
|
|
475
|
+
return b
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Replace returns a copy of the slice s with the first n
|
|
479
|
+
// non-overlapping instances of old replaced by new.
|
|
480
|
+
// If old is empty, it matches at the beginning of the slice
|
|
481
|
+
// and after each UTF-8 sequence, yielding up to k+1 replacements
|
|
482
|
+
// for a k-rune slice.
|
|
483
|
+
// If n < 0, there is no limit on the number of replacements.
|
|
484
|
+
func Replace(s, old, new []byte, n int) []byte {
|
|
485
|
+
m := 0
|
|
486
|
+
if n != 0 {
|
|
487
|
+
m = Count(s, old)
|
|
488
|
+
}
|
|
489
|
+
if m == 0 {
|
|
490
|
+
return append([]byte(nil), s...)
|
|
491
|
+
}
|
|
492
|
+
if n < 0 || m < n {
|
|
493
|
+
n = m
|
|
494
|
+
}
|
|
495
|
+
t := make([]byte, 0, len(s)+n*(len(new)-len(old)))
|
|
496
|
+
start := 0
|
|
497
|
+
for i := 0; i < n; i++ {
|
|
498
|
+
j := start
|
|
499
|
+
if len(old) == 0 {
|
|
500
|
+
if i > 0 {
|
|
501
|
+
_, wid := decodeRune(s[start:])
|
|
502
|
+
j += wid
|
|
503
|
+
}
|
|
504
|
+
} else {
|
|
505
|
+
j += Index(s[start:], old)
|
|
506
|
+
}
|
|
507
|
+
t = append(t, s[start:j]...)
|
|
508
|
+
t = append(t, new...)
|
|
509
|
+
start = j + len(old)
|
|
510
|
+
}
|
|
511
|
+
t = append(t, s[start:]...)
|
|
512
|
+
return t
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// ReplaceAll returns a copy of the slice s with all
|
|
516
|
+
// non-overlapping instances of old replaced by new.
|
|
517
|
+
// If old is empty, it matches at the beginning of the slice
|
|
518
|
+
// and after each UTF-8 sequence, yielding up to k+1 replacements
|
|
519
|
+
// for a k-rune slice.
|
|
520
|
+
func ReplaceAll(s, old, new []byte) []byte {
|
|
521
|
+
return Replace(s, old, new, -1)
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// TrimFunc returns a subslice of s by slicing off all leading and trailing
|
|
525
|
+
// UTF-8-encoded code points c that satisfy f(c).
|
|
526
|
+
func TrimFunc(s []byte, f func(r rune) bool) []byte {
|
|
527
|
+
return TrimRightFunc(TrimLeftFunc(s, f), f)
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Trim returns a subslice of s by slicing off all leading and
|
|
531
|
+
// trailing UTF-8-encoded code points contained in cutset.
|
|
532
|
+
func Trim(s []byte, cutset string) []byte {
|
|
533
|
+
if len(s) == 0 {
|
|
534
|
+
return nil
|
|
535
|
+
}
|
|
536
|
+
if cutset == "" {
|
|
537
|
+
return s
|
|
538
|
+
}
|
|
539
|
+
in := func(r rune) bool { return containsRuneIn(cutset, r) }
|
|
540
|
+
return TrimLeftFunc(TrimRightFunc(s, in), in)
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// TrimLeft returns a subslice of s by slicing off all leading
|
|
544
|
+
// UTF-8-encoded code points contained in cutset.
|
|
545
|
+
func TrimLeft(s []byte, cutset string) []byte {
|
|
546
|
+
if len(s) == 0 {
|
|
547
|
+
return nil
|
|
548
|
+
}
|
|
549
|
+
if cutset == "" {
|
|
550
|
+
return s
|
|
551
|
+
}
|
|
552
|
+
return TrimLeftFunc(s, func(r rune) bool { return containsRuneIn(cutset, r) })
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// TrimRight returns a subslice of s by slicing off all trailing
|
|
556
|
+
// UTF-8-encoded code points that are contained in cutset.
|
|
557
|
+
func TrimRight(s []byte, cutset string) []byte {
|
|
558
|
+
if len(s) == 0 || cutset == "" {
|
|
559
|
+
return s
|
|
560
|
+
}
|
|
561
|
+
return TrimRightFunc(s, func(r rune) bool { return containsRuneIn(cutset, r) })
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// TrimSpace returns a subslice of s by slicing off all leading and
|
|
565
|
+
// trailing white space, as defined by Unicode.
|
|
566
|
+
func TrimSpace(s []byte) []byte { return TrimFunc(s, isSpace) }
|
|
567
|
+
|
|
568
|
+
// TrimPrefix returns s without the provided leading prefix string.
|
|
569
|
+
// If s doesn't start with prefix, s is returned unchanged.
|
|
570
|
+
func TrimPrefix(s, prefix []byte) []byte {
|
|
571
|
+
if HasPrefix(s, prefix) {
|
|
572
|
+
return s[len(prefix):]
|
|
573
|
+
}
|
|
574
|
+
return s
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// TrimSuffix returns s without the provided trailing suffix string.
|
|
578
|
+
// If s doesn't end with suffix, s is returned unchanged.
|
|
579
|
+
func TrimSuffix(s, suffix []byte) []byte {
|
|
580
|
+
if HasSuffix(s, suffix) {
|
|
581
|
+
return s[:len(s)-len(suffix)]
|
|
582
|
+
}
|
|
583
|
+
return s
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Compare returns an integer comparing two byte slices lexicographically.
|
|
587
|
+
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
|
|
588
|
+
// A nil argument is equivalent to an empty slice.
|
|
589
|
+
//
|
|
590
|
+
//gofront:native bytes.Compare
|
|
591
|
+
func Compare(a, b []byte) int {
|
|
592
|
+
n := len(a)
|
|
593
|
+
if len(b) < n {
|
|
594
|
+
n = len(b)
|
|
595
|
+
}
|
|
596
|
+
for i := 0; i < n; i++ {
|
|
597
|
+
if a[i] != b[i] {
|
|
598
|
+
if a[i] < b[i] {
|
|
599
|
+
return -1
|
|
600
|
+
}
|
|
601
|
+
return 1
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
if len(a) < len(b) {
|
|
605
|
+
return -1
|
|
606
|
+
}
|
|
607
|
+
if len(a) > len(b) {
|
|
608
|
+
return 1
|
|
609
|
+
}
|
|
610
|
+
return 0
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// decodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and
|
|
614
|
+
// its width in bytes, as utf8.DecodeLastRune does: an invalid or incomplete
|
|
615
|
+
// encoding is (RuneError, 1) and p must not be empty.
|
|
616
|
+
func decodeLastRune(p []byte) (rune, int) {
|
|
617
|
+
end := len(p)
|
|
618
|
+
r := rune(p[end-1])
|
|
619
|
+
if r < runeSelf {
|
|
620
|
+
return r, 1
|
|
621
|
+
}
|
|
622
|
+
start := end - 1
|
|
623
|
+
lim := end - 4
|
|
624
|
+
if lim < 0 {
|
|
625
|
+
lim = 0
|
|
626
|
+
}
|
|
627
|
+
for start--; start >= lim; start-- {
|
|
628
|
+
if p[start]&0xC0 != 0x80 {
|
|
629
|
+
break
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
if start < 0 {
|
|
633
|
+
start = 0
|
|
634
|
+
}
|
|
635
|
+
r, size := decodeRune(p[start:end])
|
|
636
|
+
if start+size != end {
|
|
637
|
+
return runeError, 1
|
|
638
|
+
}
|
|
639
|
+
return r, size
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// EqualFold reports whether s and t, interpreted as UTF-8 strings,
|
|
643
|
+
// are equal under simple Unicode case-folding, which is a more general
|
|
644
|
+
// form of case-insensitivity.
|
|
645
|
+
func EqualFold(s, t []byte) bool {
|
|
646
|
+
for len(s) != 0 && len(t) != 0 {
|
|
647
|
+
var sr, tr rune
|
|
648
|
+
if s[0] < runeSelf {
|
|
649
|
+
sr, s = rune(s[0]), s[1:]
|
|
650
|
+
} else {
|
|
651
|
+
r, size := decodeRune(s)
|
|
652
|
+
sr, s = r, s[size:]
|
|
653
|
+
}
|
|
654
|
+
if t[0] < runeSelf {
|
|
655
|
+
tr, t = rune(t[0]), t[1:]
|
|
656
|
+
} else {
|
|
657
|
+
r, size := decodeRune(t)
|
|
658
|
+
tr, t = r, t[size:]
|
|
659
|
+
}
|
|
660
|
+
if tr == sr {
|
|
661
|
+
continue
|
|
662
|
+
}
|
|
663
|
+
if tr < sr {
|
|
664
|
+
tr, sr = sr, tr
|
|
665
|
+
}
|
|
666
|
+
if tr < runeSelf {
|
|
667
|
+
if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' {
|
|
668
|
+
continue
|
|
669
|
+
}
|
|
670
|
+
return false
|
|
671
|
+
}
|
|
672
|
+
r := unicode.SimpleFold(sr)
|
|
673
|
+
for r != sr && r < tr {
|
|
674
|
+
r = unicode.SimpleFold(r)
|
|
675
|
+
}
|
|
676
|
+
if r == tr {
|
|
677
|
+
continue
|
|
678
|
+
}
|
|
679
|
+
return false
|
|
680
|
+
}
|
|
681
|
+
return len(s) == len(t)
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// IndexRune interprets s as a sequence of UTF-8-encoded code points.
|
|
685
|
+
// It returns the byte index of the first occurrence in s of the given rune.
|
|
686
|
+
// It returns -1 if rune is not present in s.
|
|
687
|
+
// If r is utf8.RuneError, it returns the first instance of any
|
|
688
|
+
// invalid UTF-8 byte sequence.
|
|
689
|
+
func IndexRune(s []byte, r rune) int {
|
|
690
|
+
if r < 0 || r > 0x10FFFF || (r >= 0xD800 && r <= 0xDFFF) {
|
|
691
|
+
return -1
|
|
692
|
+
}
|
|
693
|
+
if r < runeSelf {
|
|
694
|
+
return IndexByte(s, byte(r))
|
|
695
|
+
}
|
|
696
|
+
for i := 0; i < len(s); {
|
|
697
|
+
c, size := decodeRune(s[i:])
|
|
698
|
+
if c == r {
|
|
699
|
+
return i
|
|
700
|
+
}
|
|
701
|
+
i += size
|
|
702
|
+
}
|
|
703
|
+
return -1
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// containsRuneIn reports whether chars contains r, treating an invalid sequence
|
|
707
|
+
// in chars as utf8.RuneError.
|
|
708
|
+
func containsRuneIn(chars string, r rune) bool {
|
|
709
|
+
for _, c := range chars {
|
|
710
|
+
if c == r {
|
|
711
|
+
return true
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return false
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// IndexAny interprets s as a sequence of UTF-8-encoded Unicode code points.
|
|
718
|
+
// It returns the byte index of the first occurrence in s of any of the Unicode
|
|
719
|
+
// code points in chars. It returns -1 if chars is empty or if there is no code
|
|
720
|
+
// point in common.
|
|
721
|
+
func IndexAny(s []byte, chars string) int {
|
|
722
|
+
if len(chars) == 0 {
|
|
723
|
+
return -1
|
|
724
|
+
}
|
|
725
|
+
for i := 0; i < len(s); {
|
|
726
|
+
r, size := decodeRune(s[i:])
|
|
727
|
+
if containsRuneIn(chars, r) {
|
|
728
|
+
return i
|
|
729
|
+
}
|
|
730
|
+
i += size
|
|
731
|
+
}
|
|
732
|
+
return -1
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// LastIndexAny interprets s as a sequence of UTF-8-encoded Unicode code
|
|
736
|
+
// points. It returns the byte index of the last occurrence in s of any of
|
|
737
|
+
// the Unicode code points in chars. It returns -1 if chars is empty or if
|
|
738
|
+
// there is no code point in common.
|
|
739
|
+
func LastIndexAny(s []byte, chars string) int {
|
|
740
|
+
if len(chars) == 0 {
|
|
741
|
+
return -1
|
|
742
|
+
}
|
|
743
|
+
for i := len(s); i > 0; {
|
|
744
|
+
r, size := decodeLastRune(s[:i])
|
|
745
|
+
i -= size
|
|
746
|
+
if containsRuneIn(chars, r) {
|
|
747
|
+
return i
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
return -1
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
func indexFunc(s []byte, f func(rune) bool, truth bool) int {
|
|
754
|
+
for i := 0; i < len(s); {
|
|
755
|
+
r, size := decodeRune(s[i:])
|
|
756
|
+
if f(r) == truth {
|
|
757
|
+
return i
|
|
758
|
+
}
|
|
759
|
+
i += size
|
|
760
|
+
}
|
|
761
|
+
return -1
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
func lastIndexFunc(s []byte, f func(rune) bool, truth bool) int {
|
|
765
|
+
for i := len(s); i > 0; {
|
|
766
|
+
r, size := decodeLastRune(s[:i])
|
|
767
|
+
i -= size
|
|
768
|
+
if f(r) == truth {
|
|
769
|
+
return i
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return -1
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// IndexFunc interprets s as a sequence of UTF-8-encoded code points.
|
|
776
|
+
// It returns the byte index in s of the first Unicode
|
|
777
|
+
// code point satisfying f(c), or -1 if none do.
|
|
778
|
+
func IndexFunc(s []byte, f func(r rune) bool) int {
|
|
779
|
+
return indexFunc(s, f, true)
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// LastIndexFunc interprets s as a sequence of UTF-8-encoded code points.
|
|
783
|
+
// It returns the byte index in s of the last Unicode
|
|
784
|
+
// code point satisfying f(c), or -1 if none do.
|
|
785
|
+
func LastIndexFunc(s []byte, f func(r rune) bool) int {
|
|
786
|
+
return lastIndexFunc(s, f, true)
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// ContainsFunc reports whether any of the UTF-8-encoded code points
|
|
790
|
+
// in b satisfy f(c).
|
|
791
|
+
func ContainsFunc(b []byte, f func(rune) bool) bool {
|
|
792
|
+
return indexFunc(b, f, true) >= 0
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// CutPrefix returns s without the provided leading prefix byte slice
|
|
796
|
+
// and reports whether it found the prefix.
|
|
797
|
+
// If s doesn't start with prefix, CutPrefix returns s, false.
|
|
798
|
+
// If prefix is the empty byte slice, CutPrefix returns s, true.
|
|
799
|
+
func CutPrefix(s, prefix []byte) (after []byte, found bool) {
|
|
800
|
+
if len(s) < len(prefix) || Compare(s[:len(prefix)], prefix) != 0 {
|
|
801
|
+
return s, false
|
|
802
|
+
}
|
|
803
|
+
return s[len(prefix):], true
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// CutSuffix returns s without the provided ending suffix byte slice
|
|
807
|
+
// and reports whether it found the suffix.
|
|
808
|
+
// If s doesn't end with suffix, CutSuffix returns s, false.
|
|
809
|
+
// If suffix is the empty byte slice, CutSuffix returns s, true.
|
|
810
|
+
func CutSuffix(s, suffix []byte) (before []byte, found bool) {
|
|
811
|
+
if len(s) < len(suffix) || Compare(s[len(s)-len(suffix):], suffix) != 0 {
|
|
812
|
+
return s, false
|
|
813
|
+
}
|
|
814
|
+
return s[:len(s)-len(suffix)], true
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// runeCount returns the number of runes in p, counting each invalid byte as
|
|
818
|
+
// one rune as utf8.RuneCount does.
|
|
819
|
+
func runeCount(p []byte) int {
|
|
820
|
+
n := 0
|
|
821
|
+
for i := 0; i < len(p); n++ {
|
|
822
|
+
_, size := decodeRune(p[i:])
|
|
823
|
+
i += size
|
|
824
|
+
}
|
|
825
|
+
return n
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// countSep counts the non-overlapping instances of sep in s; sep must not be
|
|
829
|
+
// empty.
|
|
830
|
+
func countSep(s, sep []byte) int {
|
|
831
|
+
n := 0
|
|
832
|
+
for {
|
|
833
|
+
i := Index(s, sep)
|
|
834
|
+
if i < 0 {
|
|
835
|
+
return n
|
|
836
|
+
}
|
|
837
|
+
n++
|
|
838
|
+
s = s[i+len(sep):]
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// explode splits s into a slice of UTF-8 sequences, one per Unicode code point
|
|
843
|
+
// (still slices of bytes), up to a maximum of n byte slices. Invalid UTF-8
|
|
844
|
+
// sequences are chopped into individual bytes.
|
|
845
|
+
func explode(s []byte, n int) [][]byte {
|
|
846
|
+
l := runeCount(s)
|
|
847
|
+
if n < 0 || n > l {
|
|
848
|
+
n = l
|
|
849
|
+
}
|
|
850
|
+
a := make([][]byte, n)
|
|
851
|
+
for i := 0; i < n-1; i++ {
|
|
852
|
+
_, size := decodeRune(s)
|
|
853
|
+
a[i] = s[:size:size]
|
|
854
|
+
s = s[size:]
|
|
855
|
+
}
|
|
856
|
+
if n > 0 {
|
|
857
|
+
a[n-1] = s[:len(s):len(s)]
|
|
858
|
+
}
|
|
859
|
+
return a
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
// genSplit splits s around sep, including sepSave bytes of sep in each
|
|
863
|
+
// subslice, into at most n subslices.
|
|
864
|
+
func genSplit(s, sep []byte, sepSave, n int) [][]byte {
|
|
865
|
+
if n == 0 {
|
|
866
|
+
return nil
|
|
867
|
+
}
|
|
868
|
+
if len(sep) == 0 {
|
|
869
|
+
return explode(s, n)
|
|
870
|
+
}
|
|
871
|
+
if n < 0 {
|
|
872
|
+
n = countSep(s, sep) + 1
|
|
873
|
+
}
|
|
874
|
+
if n > len(s)+1 {
|
|
875
|
+
n = len(s) + 1
|
|
876
|
+
}
|
|
877
|
+
a := make([][]byte, n)
|
|
878
|
+
n--
|
|
879
|
+
i := 0
|
|
880
|
+
for i < n {
|
|
881
|
+
m := Index(s, sep)
|
|
882
|
+
if m < 0 {
|
|
883
|
+
break
|
|
884
|
+
}
|
|
885
|
+
a[i] = s[: m+sepSave : m+sepSave]
|
|
886
|
+
s = s[m+len(sep):]
|
|
887
|
+
i++
|
|
888
|
+
}
|
|
889
|
+
a[i] = s[:len(s):len(s)]
|
|
890
|
+
return a[:i+1]
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// SplitAfter slices s into all subslices after each instance of sep and
|
|
894
|
+
// returns a slice of those subslices.
|
|
895
|
+
// If sep is empty, SplitAfter splits after each UTF-8 sequence.
|
|
896
|
+
// It is equivalent to SplitAfterN with a count of -1.
|
|
897
|
+
func SplitAfter(s, sep []byte) [][]byte {
|
|
898
|
+
return genSplit(s, sep, len(sep), -1)
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// SplitAfterN slices s into subslices after each instance of sep and
|
|
902
|
+
// returns a slice of those subslices.
|
|
903
|
+
// The count determines the number of subslices to return:
|
|
904
|
+
// - n > 0: at most n subslices; the last subslice will be the unsplit remainder;
|
|
905
|
+
// - n == 0: the result is nil (zero subslices);
|
|
906
|
+
// - n < 0: all subslices.
|
|
907
|
+
func SplitAfterN(s, sep []byte, n int) [][]byte {
|
|
908
|
+
return genSplit(s, sep, len(sep), n)
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// Runes interprets s as a sequence of UTF-8-encoded code points.
|
|
912
|
+
// It returns a slice of runes (Unicode code points) equivalent to s.
|
|
913
|
+
func Runes(s []byte) []rune {
|
|
914
|
+
t := make([]rune, runeCount(s))
|
|
915
|
+
i := 0
|
|
916
|
+
for len(s) > 0 {
|
|
917
|
+
r, l := decodeRune(s)
|
|
918
|
+
t[i] = r
|
|
919
|
+
i++
|
|
920
|
+
s = s[l:]
|
|
921
|
+
}
|
|
922
|
+
return t
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// isSeparator reports whether the rune could mark a word boundary.
|
|
926
|
+
func isSeparator(r rune) bool {
|
|
927
|
+
if r <= 0x7F {
|
|
928
|
+
switch {
|
|
929
|
+
case '0' <= r && r <= '9':
|
|
930
|
+
return false
|
|
931
|
+
case 'a' <= r && r <= 'z':
|
|
932
|
+
return false
|
|
933
|
+
case 'A' <= r && r <= 'Z':
|
|
934
|
+
return false
|
|
935
|
+
case r == '_':
|
|
936
|
+
return false
|
|
937
|
+
}
|
|
938
|
+
return true
|
|
939
|
+
}
|
|
940
|
+
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
|
941
|
+
return false
|
|
942
|
+
}
|
|
943
|
+
return unicode.IsSpace(r)
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// appendRune appends the UTF-8 encoding of r to p, writing RuneError for a
|
|
947
|
+
// value that is not a valid code point.
|
|
948
|
+
// The continuation bytes mask a byte(r>>n) rather than r>>n: the JS backend
|
|
949
|
+
// drops the parentheses around a wrapped int32 shift in `x | r>>n&m`.
|
|
950
|
+
func appendRune(p []byte, r rune) []byte {
|
|
951
|
+
switch {
|
|
952
|
+
case r < 0 || r > 0x10FFFF || (r >= 0xD800 && r <= 0xDFFF):
|
|
953
|
+
r = runeError
|
|
954
|
+
case r < 0x80:
|
|
955
|
+
return append(p, byte(r))
|
|
956
|
+
}
|
|
957
|
+
switch {
|
|
958
|
+
case r < 0x800:
|
|
959
|
+
return append(p, byte(0xC0|r>>6), byte(0x80|r&0x3F))
|
|
960
|
+
case r < 0x10000:
|
|
961
|
+
return append(p, byte(0xE0|r>>12), 0x80|byte(r>>6)&0x3F, byte(0x80|r&0x3F))
|
|
962
|
+
}
|
|
963
|
+
return append(p, byte(0xF0|r>>18), 0x80|byte(r>>12)&0x3F, 0x80|byte(r>>6)&0x3F, byte(0x80|r&0x3F))
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// Title treats s as UTF-8-encoded bytes and returns a copy with all Unicode
|
|
967
|
+
// letters that begin words mapped to their title case.
|
|
968
|
+
//
|
|
969
|
+
// Deprecated: The rule Title uses for word boundaries does not handle Unicode
|
|
970
|
+
// punctuation properly.
|
|
971
|
+
func Title(s []byte) []byte {
|
|
972
|
+
prev := rune(' ')
|
|
973
|
+
out := make([]byte, 0, len(s))
|
|
974
|
+
for i := 0; i < len(s); {
|
|
975
|
+
r, size := decodeRune(s[i:])
|
|
976
|
+
i += size
|
|
977
|
+
c := r
|
|
978
|
+
if isSeparator(prev) {
|
|
979
|
+
c = unicode.ToTitle(r)
|
|
980
|
+
}
|
|
981
|
+
prev = r
|
|
982
|
+
if c >= 0 {
|
|
983
|
+
out = appendRune(out, c)
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
return out
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// TrimLeftFunc treats s as UTF-8-encoded bytes and returns a subslice of s by slicing off
|
|
990
|
+
// all leading UTF-8-encoded code points c that satisfy f(c).
|
|
991
|
+
func TrimLeftFunc(s []byte, f func(r rune) bool) []byte {
|
|
992
|
+
i := indexFunc(s, f, false)
|
|
993
|
+
if i == -1 {
|
|
994
|
+
return nil
|
|
995
|
+
}
|
|
996
|
+
return s[i:]
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// TrimRightFunc returns a subslice of s by slicing off all trailing
|
|
1000
|
+
// UTF-8-encoded code points c that satisfy f(c).
|
|
1001
|
+
func TrimRightFunc(s []byte, f func(r rune) bool) []byte {
|
|
1002
|
+
i := lastIndexFunc(s, f, false)
|
|
1003
|
+
if i >= 0 && s[i] >= runeSelf {
|
|
1004
|
+
_, wid := decodeRune(s[i:])
|
|
1005
|
+
i += wid
|
|
1006
|
+
} else {
|
|
1007
|
+
i++
|
|
1008
|
+
}
|
|
1009
|
+
return s[0:i]
|
|
1010
|
+
}
|