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,209 @@
|
|
|
1
|
+
//go:build gofront
|
|
2
|
+
|
|
3
|
+
//gofront:target both
|
|
4
|
+
|
|
5
|
+
// Copyright 2023 The Go Authors. All rights reserved.
|
|
6
|
+
// Use of this source code is governed by a BSD-style
|
|
7
|
+
// license that can be found in the LICENSE file.
|
|
8
|
+
|
|
9
|
+
//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -generic
|
|
10
|
+
|
|
11
|
+
package slices
|
|
12
|
+
|
|
13
|
+
import "cmp"
|
|
14
|
+
|
|
15
|
+
// Sort sorts a slice of any ordered type in ascending order.
|
|
16
|
+
// When sorting floating-point numbers, NaNs are ordered before other values.
|
|
17
|
+
//gofront:native slices.Sort
|
|
18
|
+
func Sort[S ~[]E, E cmp.Ordered](x S) {
|
|
19
|
+
n := len(x)
|
|
20
|
+
pdqsortOrdered(x, 0, n, bitsLen(uint(n)))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// SortFunc sorts the slice x in ascending order as determined by the cmp
|
|
24
|
+
// function. This sort is not guaranteed to be stable.
|
|
25
|
+
// cmp(a, b) should return a negative number when a < b, a positive number when
|
|
26
|
+
// a > b and zero when a == b or a and b are incomparable in the sense of
|
|
27
|
+
// a strict weak ordering.
|
|
28
|
+
//
|
|
29
|
+
// SortFunc requires that cmp is a strict weak ordering.
|
|
30
|
+
// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
|
|
31
|
+
// The function should return 0 for incomparable items.
|
|
32
|
+
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
|
|
33
|
+
n := len(x)
|
|
34
|
+
pdqsortCmpFunc(x, 0, n, bitsLen(uint(n)), cmp)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// SortStableFunc sorts the slice x while keeping the original order of equal
|
|
38
|
+
// elements, using cmp to compare elements in the same way as [SortFunc].
|
|
39
|
+
func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
|
|
40
|
+
stableCmpFunc(x, len(x), cmp)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// IsSorted reports whether x is sorted in ascending order.
|
|
44
|
+
func IsSorted[S ~[]E, E cmp.Ordered](x S) bool {
|
|
45
|
+
for i := len(x) - 1; i > 0; i-- {
|
|
46
|
+
if cmp.Less(x[i], x[i-1]) {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
|
|
54
|
+
// comparison function as defined by [SortFunc].
|
|
55
|
+
func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
|
|
56
|
+
for i := len(x) - 1; i > 0; i-- {
|
|
57
|
+
if cmp(x[i], x[i-1]) < 0 {
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Min returns the minimal value in x. It panics if x is empty.
|
|
65
|
+
// For floating-point numbers, Min propagates NaNs (any NaN value in x
|
|
66
|
+
// forces the output to be NaN).
|
|
67
|
+
func Min[S ~[]E, E cmp.Ordered](x S) E {
|
|
68
|
+
if len(x) < 1 {
|
|
69
|
+
panic("slices.Min: empty list")
|
|
70
|
+
}
|
|
71
|
+
m := x[0]
|
|
72
|
+
for i := 1; i < len(x); i++ {
|
|
73
|
+
m = min(m, x[i])
|
|
74
|
+
}
|
|
75
|
+
return m
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// MinFunc returns the minimal value in x, using cmp to compare elements.
|
|
79
|
+
// It panics if x is empty. If there is more than one minimal element
|
|
80
|
+
// according to the cmp function, MinFunc returns the first one.
|
|
81
|
+
func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
|
|
82
|
+
if len(x) < 1 {
|
|
83
|
+
panic("slices.MinFunc: empty list")
|
|
84
|
+
}
|
|
85
|
+
m := x[0]
|
|
86
|
+
for i := 1; i < len(x); i++ {
|
|
87
|
+
if cmp(x[i], m) < 0 {
|
|
88
|
+
m = x[i]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return m
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Max returns the maximal value in x. It panics if x is empty.
|
|
95
|
+
// For floating-point E, Max propagates NaNs (any NaN value in x
|
|
96
|
+
// forces the output to be NaN).
|
|
97
|
+
func Max[S ~[]E, E cmp.Ordered](x S) E {
|
|
98
|
+
if len(x) < 1 {
|
|
99
|
+
panic("slices.Max: empty list")
|
|
100
|
+
}
|
|
101
|
+
m := x[0]
|
|
102
|
+
for i := 1; i < len(x); i++ {
|
|
103
|
+
m = max(m, x[i])
|
|
104
|
+
}
|
|
105
|
+
return m
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// MaxFunc returns the maximal value in x, using cmp to compare elements.
|
|
109
|
+
// It panics if x is empty. If there is more than one maximal element
|
|
110
|
+
// according to the cmp function, MaxFunc returns the first one.
|
|
111
|
+
func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
|
|
112
|
+
if len(x) < 1 {
|
|
113
|
+
panic("slices.MaxFunc: empty list")
|
|
114
|
+
}
|
|
115
|
+
m := x[0]
|
|
116
|
+
for i := 1; i < len(x); i++ {
|
|
117
|
+
if cmp(x[i], m) > 0 {
|
|
118
|
+
m = x[i]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return m
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// BinarySearch searches for target in a sorted slice and returns the earliest
|
|
125
|
+
// position where target is found, or the position where target would appear
|
|
126
|
+
// in the sort order; it also returns a bool saying whether the target is
|
|
127
|
+
// really found in the slice. The slice must be sorted in increasing order.
|
|
128
|
+
func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) {
|
|
129
|
+
// Inlining is faster than calling BinarySearchFunc with a lambda.
|
|
130
|
+
n := len(x)
|
|
131
|
+
// Define x[-1] < target and x[n] >= target.
|
|
132
|
+
// Invariant: x[i-1] < target, x[j] >= target.
|
|
133
|
+
i, j := 0, n
|
|
134
|
+
for i < j {
|
|
135
|
+
h := int(uint(i+j) >> 1) // avoid overflow when computing h
|
|
136
|
+
// i ≤ h < j
|
|
137
|
+
if cmp.Less(x[h], target) {
|
|
138
|
+
i = h + 1 // preserves x[i-1] < target
|
|
139
|
+
} else {
|
|
140
|
+
j = h // preserves x[j] >= target
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i.
|
|
144
|
+
return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target)))
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// BinarySearchFunc works like [BinarySearch], but uses a custom comparison
|
|
148
|
+
// function. The slice must be sorted in increasing order, where "increasing"
|
|
149
|
+
// is defined by cmp. cmp should return 0 if the slice element matches
|
|
150
|
+
// the target, a negative number if the slice element precedes the target,
|
|
151
|
+
// or a positive number if the slice element follows the target.
|
|
152
|
+
// cmp must implement the same ordering as the slice, such that if
|
|
153
|
+
// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
|
|
154
|
+
func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
|
|
155
|
+
n := len(x)
|
|
156
|
+
// Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 .
|
|
157
|
+
// Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0.
|
|
158
|
+
i, j := 0, n
|
|
159
|
+
for i < j {
|
|
160
|
+
h := int(uint(i+j) >> 1) // avoid overflow when computing h
|
|
161
|
+
// i ≤ h < j
|
|
162
|
+
if cmp(x[h], target) < 0 {
|
|
163
|
+
i = h + 1 // preserves cmp(x[i - 1], target) < 0
|
|
164
|
+
} else {
|
|
165
|
+
j = h // preserves cmp(x[j], target) >= 0
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i.
|
|
169
|
+
return i, i < n && cmp(x[i], target) == 0
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
type sortedHint int // hint for pdqsort when choosing the pivot
|
|
173
|
+
|
|
174
|
+
const (
|
|
175
|
+
unknownHint sortedHint = iota
|
|
176
|
+
increasingHint
|
|
177
|
+
decreasingHint
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
|
|
181
|
+
type xorshift uint64
|
|
182
|
+
|
|
183
|
+
func (r *xorshift) Next() uint64 {
|
|
184
|
+
*r ^= *r << 13
|
|
185
|
+
*r ^= *r >> 7
|
|
186
|
+
*r ^= *r << 17
|
|
187
|
+
return uint64(*r)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// bitsLen returns the minimum number of bits required to represent n; it
|
|
191
|
+
// is math/bits.Len for a uint.
|
|
192
|
+
func bitsLen(n uint) int {
|
|
193
|
+
var l int
|
|
194
|
+
for n > 0 {
|
|
195
|
+
l++
|
|
196
|
+
n >>= 1
|
|
197
|
+
}
|
|
198
|
+
return l
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
func nextPowerOfTwo(length int) uint {
|
|
202
|
+
return 1 << bitsLen(uint(length))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// isNaN reports whether x is a NaN without requiring the math package.
|
|
206
|
+
// This will always return false if T is not floating-point.
|
|
207
|
+
func isNaN[T cmp.Ordered](x T) bool {
|
|
208
|
+
return x != x
|
|
209
|
+
}
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
// Code generated by scripts/gen-pdq.js; DO NOT EDIT.
|
|
2
|
+
|
|
3
|
+
// Copyright 2022 The Go Authors. All rights reserved.
|
|
4
|
+
// Use of this source code is governed by a BSD-style
|
|
5
|
+
// license that can be found in the LICENSE file.
|
|
6
|
+
|
|
7
|
+
package slices
|
|
8
|
+
|
|
9
|
+
// insertionSortCmpFunc sorts data[a:b] using insertion sort.
|
|
10
|
+
func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
|
11
|
+
for i := a + 1; i < b; i++ {
|
|
12
|
+
for j := i; j > a && (cmp(data[j], data[j-1]) < 0); j-- {
|
|
13
|
+
data[j], data[j-1] = data[j-1], data[j]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// siftDownCmpFunc implements the heap property on data[lo:hi].
|
|
19
|
+
// first is an offset into the array where the root of the heap lies.
|
|
20
|
+
func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) {
|
|
21
|
+
root := lo
|
|
22
|
+
for {
|
|
23
|
+
child := 2*root + 1
|
|
24
|
+
if child >= hi {
|
|
25
|
+
break
|
|
26
|
+
}
|
|
27
|
+
if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) {
|
|
28
|
+
child++
|
|
29
|
+
}
|
|
30
|
+
if !(cmp(data[first+root], data[first+child]) < 0) {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
data[first+root], data[first+child] = data[first+child], data[first+root]
|
|
34
|
+
root = child
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
|
39
|
+
first := a
|
|
40
|
+
lo := 0
|
|
41
|
+
hi := b - a
|
|
42
|
+
|
|
43
|
+
// Build heap with greatest element at top.
|
|
44
|
+
for i := (hi - 1) / 2; i >= 0; i-- {
|
|
45
|
+
siftDownCmpFunc(data, i, hi, first, cmp)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Pop elements, largest first, into end of data.
|
|
49
|
+
for i := hi - 1; i >= 0; i-- {
|
|
50
|
+
data[first], data[first+i] = data[first+i], data[first]
|
|
51
|
+
siftDownCmpFunc(data, lo, i, first, cmp)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// pdqsortCmpFunc sorts data[a:b].
|
|
56
|
+
// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
|
|
57
|
+
// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
|
|
58
|
+
// C++ implementation: https://github.com/orlp/pdqsort
|
|
59
|
+
// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
|
|
60
|
+
// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
|
|
61
|
+
func pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) {
|
|
62
|
+
const maxInsertion = 12
|
|
63
|
+
|
|
64
|
+
var (
|
|
65
|
+
wasBalanced = true // whether the last partitioning was reasonably balanced
|
|
66
|
+
wasPartitioned = true // whether the slice was already partitioned
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
for {
|
|
70
|
+
length := b - a
|
|
71
|
+
|
|
72
|
+
if length <= maxInsertion {
|
|
73
|
+
insertionSortCmpFunc(data, a, b, cmp)
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Fall back to heapsort if too many bad choices were made.
|
|
78
|
+
if limit == 0 {
|
|
79
|
+
heapSortCmpFunc(data, a, b, cmp)
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// If the last partitioning was imbalanced, we need to breaking patterns.
|
|
84
|
+
if !wasBalanced {
|
|
85
|
+
breakPatternsCmpFunc(data, a, b, cmp)
|
|
86
|
+
limit--
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pivot, hint := choosePivotCmpFunc(data, a, b, cmp)
|
|
90
|
+
if hint == decreasingHint {
|
|
91
|
+
reverseRangeCmpFunc(data, a, b, cmp)
|
|
92
|
+
// The chosen pivot was pivot-a elements after the start of the array.
|
|
93
|
+
// After reversing it is pivot-a elements before the end of the array.
|
|
94
|
+
// The idea came from Rust's implementation.
|
|
95
|
+
pivot = (b - 1) - (pivot - a)
|
|
96
|
+
hint = increasingHint
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// The slice is likely already sorted.
|
|
100
|
+
if wasBalanced && wasPartitioned && hint == increasingHint {
|
|
101
|
+
if partialInsertionSortCmpFunc(data, a, b, cmp) {
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Probably the slice contains many duplicate elements, partition the slice into
|
|
107
|
+
// elements equal to and elements greater than the pivot.
|
|
108
|
+
if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) {
|
|
109
|
+
mid := partitionEqualCmpFunc(data, a, b, pivot, cmp)
|
|
110
|
+
a = mid
|
|
111
|
+
continue
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
mid, alreadyPartitioned := partitionCmpFunc(data, a, b, pivot, cmp)
|
|
115
|
+
wasPartitioned = alreadyPartitioned
|
|
116
|
+
|
|
117
|
+
leftLen, rightLen := mid-a, b-mid
|
|
118
|
+
balanceThreshold := length / 8
|
|
119
|
+
if leftLen < rightLen {
|
|
120
|
+
wasBalanced = leftLen >= balanceThreshold
|
|
121
|
+
pdqsortCmpFunc(data, a, mid, limit, cmp)
|
|
122
|
+
a = mid + 1
|
|
123
|
+
} else {
|
|
124
|
+
wasBalanced = rightLen >= balanceThreshold
|
|
125
|
+
pdqsortCmpFunc(data, mid+1, b, limit, cmp)
|
|
126
|
+
b = mid
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// partitionCmpFunc does one quicksort partition.
|
|
132
|
+
// Let p = data[pivot]
|
|
133
|
+
// Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
|
|
134
|
+
// On return, data[newpivot] = p
|
|
135
|
+
func partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) {
|
|
136
|
+
data[a], data[pivot] = data[pivot], data[a]
|
|
137
|
+
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
|
|
138
|
+
|
|
139
|
+
for i <= j && (cmp(data[i], data[a]) < 0) {
|
|
140
|
+
i++
|
|
141
|
+
}
|
|
142
|
+
for i <= j && !(cmp(data[j], data[a]) < 0) {
|
|
143
|
+
j--
|
|
144
|
+
}
|
|
145
|
+
if i > j {
|
|
146
|
+
data[j], data[a] = data[a], data[j]
|
|
147
|
+
return j, true
|
|
148
|
+
}
|
|
149
|
+
data[i], data[j] = data[j], data[i]
|
|
150
|
+
i++
|
|
151
|
+
j--
|
|
152
|
+
|
|
153
|
+
for {
|
|
154
|
+
for i <= j && (cmp(data[i], data[a]) < 0) {
|
|
155
|
+
i++
|
|
156
|
+
}
|
|
157
|
+
for i <= j && !(cmp(data[j], data[a]) < 0) {
|
|
158
|
+
j--
|
|
159
|
+
}
|
|
160
|
+
if i > j {
|
|
161
|
+
break
|
|
162
|
+
}
|
|
163
|
+
data[i], data[j] = data[j], data[i]
|
|
164
|
+
i++
|
|
165
|
+
j--
|
|
166
|
+
}
|
|
167
|
+
data[j], data[a] = data[a], data[j]
|
|
168
|
+
return j, false
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// partitionEqualCmpFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
|
|
172
|
+
// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
|
|
173
|
+
func partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) {
|
|
174
|
+
data[a], data[pivot] = data[pivot], data[a]
|
|
175
|
+
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
|
|
176
|
+
|
|
177
|
+
for {
|
|
178
|
+
for i <= j && !(cmp(data[a], data[i]) < 0) {
|
|
179
|
+
i++
|
|
180
|
+
}
|
|
181
|
+
for i <= j && (cmp(data[a], data[j]) < 0) {
|
|
182
|
+
j--
|
|
183
|
+
}
|
|
184
|
+
if i > j {
|
|
185
|
+
break
|
|
186
|
+
}
|
|
187
|
+
data[i], data[j] = data[j], data[i]
|
|
188
|
+
i++
|
|
189
|
+
j--
|
|
190
|
+
}
|
|
191
|
+
return i
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end.
|
|
195
|
+
func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool {
|
|
196
|
+
const (
|
|
197
|
+
maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
|
|
198
|
+
shortestShifting = 50 // don't shift any elements on short arrays
|
|
199
|
+
)
|
|
200
|
+
i := a + 1
|
|
201
|
+
for j := 0; j < maxSteps; j++ {
|
|
202
|
+
for i < b && !(cmp(data[i], data[i-1]) < 0) {
|
|
203
|
+
i++
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if i == b {
|
|
207
|
+
return true
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if b-a < shortestShifting {
|
|
211
|
+
return false
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
data[i], data[i-1] = data[i-1], data[i]
|
|
215
|
+
|
|
216
|
+
// Shift the smaller one to the left.
|
|
217
|
+
if i-a >= 2 {
|
|
218
|
+
for j := i - 1; j >= 1; j-- {
|
|
219
|
+
if !(cmp(data[j], data[j-1]) < 0) {
|
|
220
|
+
break
|
|
221
|
+
}
|
|
222
|
+
data[j], data[j-1] = data[j-1], data[j]
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Shift the greater one to the right.
|
|
226
|
+
if b-i >= 2 {
|
|
227
|
+
for j := i + 1; j < b; j++ {
|
|
228
|
+
if !(cmp(data[j], data[j-1]) < 0) {
|
|
229
|
+
break
|
|
230
|
+
}
|
|
231
|
+
data[j], data[j-1] = data[j-1], data[j]
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return false
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns
|
|
239
|
+
// that might cause imbalanced partitions in quicksort.
|
|
240
|
+
func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
|
241
|
+
length := b - a
|
|
242
|
+
if length >= 8 {
|
|
243
|
+
random := xorshift(length)
|
|
244
|
+
modulus := nextPowerOfTwo(length)
|
|
245
|
+
|
|
246
|
+
for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
|
|
247
|
+
// Masked as a uint64 first: Go's uint(random.Next()) would round a value above 2^53 on JS.
|
|
248
|
+
other := int(random.Next() & uint64(modulus-1))
|
|
249
|
+
if other >= length {
|
|
250
|
+
other -= length
|
|
251
|
+
}
|
|
252
|
+
data[idx], data[a+other] = data[a+other], data[idx]
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// choosePivotCmpFunc chooses a pivot in data[a:b].
|
|
258
|
+
//
|
|
259
|
+
// [0,8): chooses a static pivot.
|
|
260
|
+
// [8,shortestNinther): uses the simple median-of-three method.
|
|
261
|
+
// [shortestNinther,∞): uses the Tukey ninther method.
|
|
262
|
+
func choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) {
|
|
263
|
+
const (
|
|
264
|
+
shortestNinther = 50
|
|
265
|
+
maxSwaps = 4 * 3
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
l := b - a
|
|
269
|
+
|
|
270
|
+
var (
|
|
271
|
+
swaps int
|
|
272
|
+
i = a + l/4*1
|
|
273
|
+
j = a + l/4*2
|
|
274
|
+
k = a + l/4*3
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
if l >= 8 {
|
|
278
|
+
if l >= shortestNinther {
|
|
279
|
+
// Tukey ninther method, the idea came from Rust's implementation.
|
|
280
|
+
i = medianAdjacentCmpFunc(data, i, &swaps, cmp)
|
|
281
|
+
j = medianAdjacentCmpFunc(data, j, &swaps, cmp)
|
|
282
|
+
k = medianAdjacentCmpFunc(data, k, &swaps, cmp)
|
|
283
|
+
}
|
|
284
|
+
// Find the median among i, j, k and stores it into j.
|
|
285
|
+
j = medianCmpFunc(data, i, j, k, &swaps, cmp)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
switch swaps {
|
|
289
|
+
case 0:
|
|
290
|
+
return j, increasingHint
|
|
291
|
+
case maxSwaps:
|
|
292
|
+
return j, decreasingHint
|
|
293
|
+
default:
|
|
294
|
+
return j, unknownHint
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
|
|
299
|
+
func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) {
|
|
300
|
+
if cmp(data[b], data[a]) < 0 {
|
|
301
|
+
*swaps++
|
|
302
|
+
return b, a
|
|
303
|
+
}
|
|
304
|
+
return a, b
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
|
|
308
|
+
func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int {
|
|
309
|
+
a, b = order2CmpFunc(data, a, b, swaps, cmp)
|
|
310
|
+
b, c = order2CmpFunc(data, b, c, swaps, cmp)
|
|
311
|
+
a, b = order2CmpFunc(data, a, b, swaps, cmp)
|
|
312
|
+
return b
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
|
|
316
|
+
func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int {
|
|
317
|
+
return medianCmpFunc(data, a-1, a, a+1, swaps, cmp)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
|
321
|
+
i := a
|
|
322
|
+
j := b - 1
|
|
323
|
+
for i < j {
|
|
324
|
+
data[i], data[j] = data[j], data[i]
|
|
325
|
+
i++
|
|
326
|
+
j--
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) {
|
|
331
|
+
for i := 0; i < n; i++ {
|
|
332
|
+
data[a+i], data[b+i] = data[b+i], data[a+i]
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) {
|
|
337
|
+
blockSize := 20 // must be > 0
|
|
338
|
+
a, b := 0, blockSize
|
|
339
|
+
for b <= n {
|
|
340
|
+
insertionSortCmpFunc(data, a, b, cmp)
|
|
341
|
+
a = b
|
|
342
|
+
b += blockSize
|
|
343
|
+
}
|
|
344
|
+
insertionSortCmpFunc(data, a, n, cmp)
|
|
345
|
+
|
|
346
|
+
for blockSize < n {
|
|
347
|
+
a, b = 0, 2*blockSize
|
|
348
|
+
for b <= n {
|
|
349
|
+
symMergeCmpFunc(data, a, a+blockSize, b, cmp)
|
|
350
|
+
a = b
|
|
351
|
+
b += 2 * blockSize
|
|
352
|
+
}
|
|
353
|
+
if m := a + blockSize; m < n {
|
|
354
|
+
symMergeCmpFunc(data, a, m, n, cmp)
|
|
355
|
+
}
|
|
356
|
+
blockSize *= 2
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// symMergeCmpFunc merges the two sorted subsequences data[a:m] and data[m:b] using
|
|
361
|
+
// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
|
|
362
|
+
// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
|
|
363
|
+
// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
|
|
364
|
+
// Computer Science, pages 714-723. Springer, 2004.
|
|
365
|
+
//
|
|
366
|
+
// Let M = m-a and N = b-n. Wolog M < N.
|
|
367
|
+
// The recursion depth is bound by ceil(log(N+M)).
|
|
368
|
+
// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
|
|
369
|
+
// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
|
|
370
|
+
//
|
|
371
|
+
// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
|
|
372
|
+
// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
|
|
373
|
+
// in the paper carries through for Swap operations, especially as the block
|
|
374
|
+
// swapping rotate uses only O(M+N) Swaps.
|
|
375
|
+
//
|
|
376
|
+
// symMerge assumes non-degenerate arguments: a < m && m < b.
|
|
377
|
+
// Having the caller check this condition eliminates many leaf recursion calls,
|
|
378
|
+
// which improves performance.
|
|
379
|
+
func symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
|
|
380
|
+
// Avoid unnecessary recursions of symMerge
|
|
381
|
+
// by direct insertion of data[a] into data[m:b]
|
|
382
|
+
// if data[a:m] only contains one element.
|
|
383
|
+
if m-a == 1 {
|
|
384
|
+
// Use binary search to find the lowest index i
|
|
385
|
+
// such that data[i] >= data[a] for m <= i < b.
|
|
386
|
+
// Exit the search loop with i == b in case no such index exists.
|
|
387
|
+
i := m
|
|
388
|
+
j := b
|
|
389
|
+
for i < j {
|
|
390
|
+
h := int(uint(i+j) >> 1)
|
|
391
|
+
if cmp(data[h], data[a]) < 0 {
|
|
392
|
+
i = h + 1
|
|
393
|
+
} else {
|
|
394
|
+
j = h
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// Swap values until data[a] reaches the position before i.
|
|
398
|
+
for k := a; k < i-1; k++ {
|
|
399
|
+
data[k], data[k+1] = data[k+1], data[k]
|
|
400
|
+
}
|
|
401
|
+
return
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Avoid unnecessary recursions of symMerge
|
|
405
|
+
// by direct insertion of data[m] into data[a:m]
|
|
406
|
+
// if data[m:b] only contains one element.
|
|
407
|
+
if b-m == 1 {
|
|
408
|
+
// Use binary search to find the lowest index i
|
|
409
|
+
// such that data[i] > data[m] for a <= i < m.
|
|
410
|
+
// Exit the search loop with i == m in case no such index exists.
|
|
411
|
+
i := a
|
|
412
|
+
j := m
|
|
413
|
+
for i < j {
|
|
414
|
+
h := int(uint(i+j) >> 1)
|
|
415
|
+
if !(cmp(data[m], data[h]) < 0) {
|
|
416
|
+
i = h + 1
|
|
417
|
+
} else {
|
|
418
|
+
j = h
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// Swap values until data[m] reaches the position i.
|
|
422
|
+
for k := m; k > i; k-- {
|
|
423
|
+
data[k], data[k-1] = data[k-1], data[k]
|
|
424
|
+
}
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
mid := int(uint(a+b) >> 1)
|
|
429
|
+
n := mid + m
|
|
430
|
+
var start, r int
|
|
431
|
+
if m > mid {
|
|
432
|
+
start = n - b
|
|
433
|
+
r = mid
|
|
434
|
+
} else {
|
|
435
|
+
start = a
|
|
436
|
+
r = m
|
|
437
|
+
}
|
|
438
|
+
p := n - 1
|
|
439
|
+
|
|
440
|
+
for start < r {
|
|
441
|
+
c := int(uint(start+r) >> 1)
|
|
442
|
+
if !(cmp(data[p-c], data[c]) < 0) {
|
|
443
|
+
start = c + 1
|
|
444
|
+
} else {
|
|
445
|
+
r = c
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
end := n - start
|
|
450
|
+
if start < m && m < end {
|
|
451
|
+
rotateCmpFunc(data, start, m, end, cmp)
|
|
452
|
+
}
|
|
453
|
+
if a < start && start < mid {
|
|
454
|
+
symMergeCmpFunc(data, a, start, mid, cmp)
|
|
455
|
+
}
|
|
456
|
+
if mid < end && end < b {
|
|
457
|
+
symMergeCmpFunc(data, mid, end, b, cmp)
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// rotateCmpFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
|
|
462
|
+
// Data of the form 'x u v y' is changed to 'x v u y'.
|
|
463
|
+
// rotate performs at most b-a many calls to data.Swap,
|
|
464
|
+
// and it assumes non-degenerate arguments: a < m && m < b.
|
|
465
|
+
func rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
|
|
466
|
+
i := m - a
|
|
467
|
+
j := b - m
|
|
468
|
+
|
|
469
|
+
for i != j {
|
|
470
|
+
if i > j {
|
|
471
|
+
swapRangeCmpFunc(data, m-i, m, j, cmp)
|
|
472
|
+
i -= j
|
|
473
|
+
} else {
|
|
474
|
+
swapRangeCmpFunc(data, m-i, m+j-i, i, cmp)
|
|
475
|
+
j -= i
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// i == j
|
|
479
|
+
swapRangeCmpFunc(data, m-i, m, i, cmp)
|
|
480
|
+
}
|