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.
Files changed (194) hide show
  1. package/README.md +14 -14
  2. package/package.json +10 -38
  3. package/src/backend/js/expressions.js +2060 -389
  4. package/src/backend/js/index.js +586 -174
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +936 -1644
  7. package/src/backend/js/statements.js +1349 -132
  8. package/src/backend/js/stdlib/index.js +51 -94
  9. package/src/backend/js/templ.js +67 -118
  10. package/src/backend/js/type-info.js +436 -0
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +80 -0
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +753 -872
  15. package/src/backend/wasm/emit-builtins.js +914 -237
  16. package/src/backend/wasm/emit-exprs.js +1456 -195
  17. package/src/backend/wasm/emit-maps.js +78 -380
  18. package/src/backend/wasm/emit-stmts.js +1659 -214
  19. package/src/backend/wasm/emit.js +614 -88
  20. package/src/backend/wasm/encode.js +43 -13
  21. package/src/backend/wasm/globals.js +491 -0
  22. package/src/backend/wasm/glue.js +2 -4
  23. package/src/backend/wasm/index.js +406 -3195
  24. package/src/backend/wasm/method-expr.js +392 -0
  25. package/src/backend/wasm/module-emitter.js +1615 -0
  26. package/src/backend/wasm/monomorph.js +164 -9
  27. package/src/backend/wasm/natives.js +596 -0
  28. package/src/backend/wasm/prescan.js +249 -0
  29. package/src/backend/wasm/prune-funcs.js +89 -0
  30. package/src/backend/wasm/stdlib/index.js +2 -37
  31. package/src/backend/wasm/stdlib/simd.js +293 -28
  32. package/src/backend/wasm/types.js +260 -27
  33. package/src/backend/wasm/variadic.js +93 -0
  34. package/src/backend/wasm/wat.js +47 -20
  35. package/src/{cli-core.js → cli/cli-core.js} +241 -11
  36. package/src/{test-runner.js → cli/test-runner.js} +188 -122
  37. package/src/{vendor.js → cli/vendor.js} +3 -4
  38. package/src/compiler.js +202 -386
  39. package/src/index.js +15 -169
  40. package/src/{lexer.js → lexer/lexer.js} +203 -62
  41. package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
  42. package/src/{tokens.js → lexer/tokens.js} +2 -0
  43. package/src/link/sourcemap.js +97 -0
  44. package/src/link/stdlib.js +737 -0
  45. package/src/link/type-names.js +148 -0
  46. package/src/link/wasm.js +318 -0
  47. package/src/lower/bounds.js +547 -0
  48. package/src/lower/boxing.js +1 -1
  49. package/src/lower/captures.js +267 -64
  50. package/src/lower/embedding.js +32 -3
  51. package/src/lower/errors-as.js +196 -0
  52. package/src/lower/fmt-formatters.js +905 -0
  53. package/src/lower/functions.js +2 -0
  54. package/src/lower/gen-types.js +274 -0
  55. package/src/lower/index.js +33 -19
  56. package/src/lower/json-codecs.js +1379 -0
  57. package/src/lower/ownership.js +47 -8
  58. package/src/lower/range.js +86 -1
  59. package/src/lower/reachability.js +150 -0
  60. package/src/lower/walk.js +12 -0
  61. package/src/parser/declarations.js +83 -15
  62. package/src/parser/expressions.js +110 -18
  63. package/src/parser/index.js +2 -1
  64. package/src/parser/statements.js +38 -22
  65. package/src/{templ-parser.js → parser/templ.js} +179 -17
  66. package/src/parser/types.js +70 -9
  67. package/src/resolver.js +21 -1
  68. package/src/typechecker/assignability.js +291 -19
  69. package/src/typechecker/const-fold.js +399 -0
  70. package/src/typechecker/constants.js +282 -0
  71. package/src/typechecker/expressions.js +1220 -183
  72. package/src/typechecker/index.js +659 -92
  73. package/src/typechecker/init-order.js +426 -0
  74. package/src/typechecker/operand-text.js +40 -0
  75. package/src/typechecker/resolve.js +613 -62
  76. package/src/typechecker/statements.js +212 -20
  77. package/src/typechecker/stdlib/excluded.js +902 -0
  78. package/src/typechecker/stdlib/index.js +38 -0
  79. package/src/typechecker/stdlib/simd.js +65 -15
  80. package/src/typechecker/termination.js +11 -2
  81. package/src/typechecker/types.js +268 -514
  82. package/stdlib/bytes/buffer.go +479 -0
  83. package/stdlib/bytes/bytes.go +1010 -0
  84. package/stdlib/bytes/reader.go +161 -0
  85. package/stdlib/cmp/cmp.go +65 -0
  86. package/stdlib/context/context.go +115 -0
  87. package/stdlib/crypto/rand/rand.go +34 -0
  88. package/stdlib/crypto/sha256/sha256.go +249 -0
  89. package/stdlib/encoding/base64/base64.go +331 -0
  90. package/stdlib/encoding/binary/binary.go +332 -0
  91. package/stdlib/encoding/hex/hex.go +140 -0
  92. package/stdlib/encoding/json/errors.go +31 -0
  93. package/stdlib/encoding/json/indent.go +71 -0
  94. package/stdlib/encoding/json/json.go +62 -0
  95. package/stdlib/encoding/json/number.go +12 -0
  96. package/stdlib/encoding/json/stream.go +173 -0
  97. package/stdlib/errors/errors.go +174 -0
  98. package/stdlib/fmt/errors.go +110 -0
  99. package/stdlib/fmt/format.go +732 -0
  100. package/stdlib/fmt/print.go +1232 -0
  101. package/stdlib/gom/gom.go +293 -0
  102. package/stdlib/hash/hash.go +53 -0
  103. package/stdlib/html/html.go +251 -0
  104. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  105. package/stdlib/internal/jsonrt/dec.go +871 -0
  106. package/stdlib/internal/jsonrt/enc.go +516 -0
  107. package/stdlib/internal/jsonrt/indent.go +135 -0
  108. package/stdlib/internal/jsonrt/number.go +27 -0
  109. package/stdlib/internal/jsonrt/reader.go +73 -0
  110. package/stdlib/internal/jsonrt/scanner.go +658 -0
  111. package/stdlib/io/io.go +502 -0
  112. package/stdlib/iter/iter.go +18 -0
  113. package/stdlib/maps/maps.go +131 -0
  114. package/stdlib/math/bits/bits.go +507 -0
  115. package/stdlib/math/extra.go +272 -0
  116. package/stdlib/math/math.go +439 -0
  117. package/stdlib/math/rand/rand.go +297 -0
  118. package/stdlib/os/os.go +93 -0
  119. package/stdlib/path/filepath/filepath.go +47 -0
  120. package/stdlib/path/path.go +394 -0
  121. package/stdlib/regexp/regexp.go +231 -0
  122. package/stdlib/slices/slices.go +526 -0
  123. package/stdlib/slices/sort.go +209 -0
  124. package/stdlib/slices/zsort_cmp.go +480 -0
  125. package/stdlib/slices/zsort_ordered.go +482 -0
  126. package/stdlib/sort/sort.go +500 -0
  127. package/stdlib/sort/zsort_func.go +480 -0
  128. package/stdlib/sort/zsort_iface.go +480 -0
  129. package/stdlib/strconv/float.go +1699 -0
  130. package/stdlib/strconv/isprint.go +752 -0
  131. package/stdlib/strconv/quote.go +526 -0
  132. package/stdlib/strconv/strconv.go +616 -0
  133. package/stdlib/strings/builder.go +95 -0
  134. package/stdlib/strings/reader.go +163 -0
  135. package/stdlib/strings/replacer.go +102 -0
  136. package/stdlib/strings/strings.go +807 -0
  137. package/stdlib/sync/sync.go +268 -0
  138. package/stdlib/testing/async_js.go +61 -0
  139. package/stdlib/testing/benchmark.go +297 -0
  140. package/stdlib/testing/testing.go +523 -0
  141. package/stdlib/time/duration.go +233 -0
  142. package/stdlib/time/format.go +745 -0
  143. package/stdlib/time/parse.go +790 -0
  144. package/stdlib/time/sleep_js.go +63 -0
  145. package/stdlib/time/time.go +834 -0
  146. package/stdlib/unicode/unicode.go +250 -0
  147. package/stdlib/unicode/utf8/utf8.go +464 -0
  148. package/src/backend/js/stdlib/base64.js +0 -12
  149. package/src/backend/js/stdlib/binary.js +0 -102
  150. package/src/backend/js/stdlib/bits.js +0 -46
  151. package/src/backend/js/stdlib/builder.js +0 -63
  152. package/src/backend/js/stdlib/bytes.js +0 -122
  153. package/src/backend/js/stdlib/errors.js +0 -44
  154. package/src/backend/js/stdlib/fmt.js +0 -178
  155. package/src/backend/js/stdlib/gom.js +0 -155
  156. package/src/backend/js/stdlib/hex.js +0 -17
  157. package/src/backend/js/stdlib/html.js +0 -20
  158. package/src/backend/js/stdlib/io.js +0 -137
  159. package/src/backend/js/stdlib/json.js +0 -972
  160. package/src/backend/js/stdlib/maps.js +0 -45
  161. package/src/backend/js/stdlib/math.js +0 -69
  162. package/src/backend/js/stdlib/os.js +0 -13
  163. package/src/backend/js/stdlib/path.js +0 -48
  164. package/src/backend/js/stdlib/rand.js +0 -32
  165. package/src/backend/js/stdlib/regexp.js +0 -54
  166. package/src/backend/js/stdlib/sha256.js +0 -12
  167. package/src/backend/js/stdlib/shared.js +0 -17
  168. package/src/backend/js/stdlib/simd.js +0 -24
  169. package/src/backend/js/stdlib/slices.js +0 -77
  170. package/src/backend/js/stdlib/sort.js +0 -30
  171. package/src/backend/js/stdlib/strconv.js +0 -74
  172. package/src/backend/js/stdlib/strings.js +0 -222
  173. package/src/backend/js/stdlib/sync.js +0 -13
  174. package/src/backend/js/stdlib/testing.js +0 -34
  175. package/src/backend/js/stdlib/time.js +0 -128
  176. package/src/backend/js/stdlib/unicode.js +0 -25
  177. package/src/backend/js/stdlib/utf8.js +0 -26
  178. package/src/backend/wasm/const-fold.js +0 -205
  179. package/src/backend/wasm/emit-stdlib.js +0 -13
  180. package/src/backend/wasm/stdlib/bytes.js +0 -5039
  181. package/src/backend/wasm/stdlib/core.js +0 -8903
  182. package/src/backend/wasm/stdlib/io.js +0 -2161
  183. package/src/backend/wasm/stdlib/packages.js +0 -2400
  184. package/src/backend/wasm/stdlib/pure.js +0 -720
  185. package/src/backend/wasm/stdlib/time.js +0 -1200
  186. package/src/typechecker/stdlib/core.js +0 -801
  187. package/src/typechecker/stdlib/extended.js +0 -914
  188. package/src/typechecker/stdlib.js +0 -22
  189. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  190. /package/src/{colors.js → cli/colors.js} +0 -0
  191. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  192. /package/src/{minifier.js → cli/minifier.js} +0 -0
  193. /package/src/{project-config.js → cli/project-config.js} +0 -0
  194. /package/src/{pwa.js → cli/pwa.js} +0 -0
@@ -0,0 +1,482 @@
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
+ import "cmp"
10
+
11
+ // insertionSortOrdered sorts data[a:b] using insertion sort.
12
+ func insertionSortOrdered[E cmp.Ordered](data []E, a, b int) {
13
+ for i := a + 1; i < b; i++ {
14
+ for j := i; j > a && cmp.Less(data[j], data[j-1]); j-- {
15
+ data[j], data[j-1] = data[j-1], data[j]
16
+ }
17
+ }
18
+ }
19
+
20
+ // siftDownOrdered implements the heap property on data[lo:hi].
21
+ // first is an offset into the array where the root of the heap lies.
22
+ func siftDownOrdered[E cmp.Ordered](data []E, lo, hi, first int) {
23
+ root := lo
24
+ for {
25
+ child := 2*root + 1
26
+ if child >= hi {
27
+ break
28
+ }
29
+ if child+1 < hi && cmp.Less(data[first+child], data[first+child+1]) {
30
+ child++
31
+ }
32
+ if !cmp.Less(data[first+root], data[first+child]) {
33
+ return
34
+ }
35
+ data[first+root], data[first+child] = data[first+child], data[first+root]
36
+ root = child
37
+ }
38
+ }
39
+
40
+ func heapSortOrdered[E cmp.Ordered](data []E, a, b int) {
41
+ first := a
42
+ lo := 0
43
+ hi := b - a
44
+
45
+ // Build heap with greatest element at top.
46
+ for i := (hi - 1) / 2; i >= 0; i-- {
47
+ siftDownOrdered(data, i, hi, first)
48
+ }
49
+
50
+ // Pop elements, largest first, into end of data.
51
+ for i := hi - 1; i >= 0; i-- {
52
+ data[first], data[first+i] = data[first+i], data[first]
53
+ siftDownOrdered(data, lo, i, first)
54
+ }
55
+ }
56
+
57
+ // pdqsortOrdered sorts data[a:b].
58
+ // The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
59
+ // pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
60
+ // C++ implementation: https://github.com/orlp/pdqsort
61
+ // Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
62
+ // limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
63
+ func pdqsortOrdered[E cmp.Ordered](data []E, a, b, limit int) {
64
+ const maxInsertion = 12
65
+
66
+ var (
67
+ wasBalanced = true // whether the last partitioning was reasonably balanced
68
+ wasPartitioned = true // whether the slice was already partitioned
69
+ )
70
+
71
+ for {
72
+ length := b - a
73
+
74
+ if length <= maxInsertion {
75
+ insertionSortOrdered(data, a, b)
76
+ return
77
+ }
78
+
79
+ // Fall back to heapsort if too many bad choices were made.
80
+ if limit == 0 {
81
+ heapSortOrdered(data, a, b)
82
+ return
83
+ }
84
+
85
+ // If the last partitioning was imbalanced, we need to breaking patterns.
86
+ if !wasBalanced {
87
+ breakPatternsOrdered(data, a, b)
88
+ limit--
89
+ }
90
+
91
+ pivot, hint := choosePivotOrdered(data, a, b)
92
+ if hint == decreasingHint {
93
+ reverseRangeOrdered(data, a, b)
94
+ // The chosen pivot was pivot-a elements after the start of the array.
95
+ // After reversing it is pivot-a elements before the end of the array.
96
+ // The idea came from Rust's implementation.
97
+ pivot = (b - 1) - (pivot - a)
98
+ hint = increasingHint
99
+ }
100
+
101
+ // The slice is likely already sorted.
102
+ if wasBalanced && wasPartitioned && hint == increasingHint {
103
+ if partialInsertionSortOrdered(data, a, b) {
104
+ return
105
+ }
106
+ }
107
+
108
+ // Probably the slice contains many duplicate elements, partition the slice into
109
+ // elements equal to and elements greater than the pivot.
110
+ if a > 0 && !cmp.Less(data[a-1], data[pivot]) {
111
+ mid := partitionEqualOrdered(data, a, b, pivot)
112
+ a = mid
113
+ continue
114
+ }
115
+
116
+ mid, alreadyPartitioned := partitionOrdered(data, a, b, pivot)
117
+ wasPartitioned = alreadyPartitioned
118
+
119
+ leftLen, rightLen := mid-a, b-mid
120
+ balanceThreshold := length / 8
121
+ if leftLen < rightLen {
122
+ wasBalanced = leftLen >= balanceThreshold
123
+ pdqsortOrdered(data, a, mid, limit)
124
+ a = mid + 1
125
+ } else {
126
+ wasBalanced = rightLen >= balanceThreshold
127
+ pdqsortOrdered(data, mid+1, b, limit)
128
+ b = mid
129
+ }
130
+ }
131
+ }
132
+
133
+ // partitionOrdered does one quicksort partition.
134
+ // Let p = data[pivot]
135
+ // Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
136
+ // On return, data[newpivot] = p
137
+ func partitionOrdered[E cmp.Ordered](data []E, a, b, pivot int) (newpivot int, alreadyPartitioned bool) {
138
+ data[a], data[pivot] = data[pivot], data[a]
139
+ i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
140
+
141
+ for i <= j && cmp.Less(data[i], data[a]) {
142
+ i++
143
+ }
144
+ for i <= j && !cmp.Less(data[j], data[a]) {
145
+ j--
146
+ }
147
+ if i > j {
148
+ data[j], data[a] = data[a], data[j]
149
+ return j, true
150
+ }
151
+ data[i], data[j] = data[j], data[i]
152
+ i++
153
+ j--
154
+
155
+ for {
156
+ for i <= j && cmp.Less(data[i], data[a]) {
157
+ i++
158
+ }
159
+ for i <= j && !cmp.Less(data[j], data[a]) {
160
+ j--
161
+ }
162
+ if i > j {
163
+ break
164
+ }
165
+ data[i], data[j] = data[j], data[i]
166
+ i++
167
+ j--
168
+ }
169
+ data[j], data[a] = data[a], data[j]
170
+ return j, false
171
+ }
172
+
173
+ // partitionEqualOrdered partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
174
+ // It assumed that data[a:b] does not contain elements smaller than the data[pivot].
175
+ func partitionEqualOrdered[E cmp.Ordered](data []E, a, b, pivot int) (newpivot int) {
176
+ data[a], data[pivot] = data[pivot], data[a]
177
+ i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
178
+
179
+ for {
180
+ for i <= j && !cmp.Less(data[a], data[i]) {
181
+ i++
182
+ }
183
+ for i <= j && cmp.Less(data[a], data[j]) {
184
+ j--
185
+ }
186
+ if i > j {
187
+ break
188
+ }
189
+ data[i], data[j] = data[j], data[i]
190
+ i++
191
+ j--
192
+ }
193
+ return i
194
+ }
195
+
196
+ // partialInsertionSortOrdered partially sorts a slice, returns true if the slice is sorted at the end.
197
+ func partialInsertionSortOrdered[E cmp.Ordered](data []E, a, b int) bool {
198
+ const (
199
+ maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
200
+ shortestShifting = 50 // don't shift any elements on short arrays
201
+ )
202
+ i := a + 1
203
+ for j := 0; j < maxSteps; j++ {
204
+ for i < b && !cmp.Less(data[i], data[i-1]) {
205
+ i++
206
+ }
207
+
208
+ if i == b {
209
+ return true
210
+ }
211
+
212
+ if b-a < shortestShifting {
213
+ return false
214
+ }
215
+
216
+ data[i], data[i-1] = data[i-1], data[i]
217
+
218
+ // Shift the smaller one to the left.
219
+ if i-a >= 2 {
220
+ for j := i - 1; j >= 1; j-- {
221
+ if !cmp.Less(data[j], data[j-1]) {
222
+ break
223
+ }
224
+ data[j], data[j-1] = data[j-1], data[j]
225
+ }
226
+ }
227
+ // Shift the greater one to the right.
228
+ if b-i >= 2 {
229
+ for j := i + 1; j < b; j++ {
230
+ if !cmp.Less(data[j], data[j-1]) {
231
+ break
232
+ }
233
+ data[j], data[j-1] = data[j-1], data[j]
234
+ }
235
+ }
236
+ }
237
+ return false
238
+ }
239
+
240
+ // breakPatternsOrdered scatters some elements around in an attempt to break some patterns
241
+ // that might cause imbalanced partitions in quicksort.
242
+ func breakPatternsOrdered[E cmp.Ordered](data []E, a, b int) {
243
+ length := b - a
244
+ if length >= 8 {
245
+ random := xorshift(length)
246
+ modulus := nextPowerOfTwo(length)
247
+
248
+ for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
249
+ // Masked as a uint64 first: Go's uint(random.Next()) would round a value above 2^53 on JS.
250
+ other := int(random.Next() & uint64(modulus-1))
251
+ if other >= length {
252
+ other -= length
253
+ }
254
+ data[idx], data[a+other] = data[a+other], data[idx]
255
+ }
256
+ }
257
+ }
258
+
259
+ // choosePivotOrdered chooses a pivot in data[a:b].
260
+ //
261
+ // [0,8): chooses a static pivot.
262
+ // [8,shortestNinther): uses the simple median-of-three method.
263
+ // [shortestNinther,∞): uses the Tukey ninther method.
264
+ func choosePivotOrdered[E cmp.Ordered](data []E, a, b int) (pivot int, hint sortedHint) {
265
+ const (
266
+ shortestNinther = 50
267
+ maxSwaps = 4 * 3
268
+ )
269
+
270
+ l := b - a
271
+
272
+ var (
273
+ swaps int
274
+ i = a + l/4*1
275
+ j = a + l/4*2
276
+ k = a + l/4*3
277
+ )
278
+
279
+ if l >= 8 {
280
+ if l >= shortestNinther {
281
+ // Tukey ninther method, the idea came from Rust's implementation.
282
+ i = medianAdjacentOrdered(data, i, &swaps)
283
+ j = medianAdjacentOrdered(data, j, &swaps)
284
+ k = medianAdjacentOrdered(data, k, &swaps)
285
+ }
286
+ // Find the median among i, j, k and stores it into j.
287
+ j = medianOrdered(data, i, j, k, &swaps)
288
+ }
289
+
290
+ switch swaps {
291
+ case 0:
292
+ return j, increasingHint
293
+ case maxSwaps:
294
+ return j, decreasingHint
295
+ default:
296
+ return j, unknownHint
297
+ }
298
+ }
299
+
300
+ // order2Ordered returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
301
+ func order2Ordered[E cmp.Ordered](data []E, a, b int, swaps *int) (int, int) {
302
+ if cmp.Less(data[b], data[a]) {
303
+ *swaps++
304
+ return b, a
305
+ }
306
+ return a, b
307
+ }
308
+
309
+ // medianOrdered returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
310
+ func medianOrdered[E cmp.Ordered](data []E, a, b, c int, swaps *int) int {
311
+ a, b = order2Ordered(data, a, b, swaps)
312
+ b, c = order2Ordered(data, b, c, swaps)
313
+ a, b = order2Ordered(data, a, b, swaps)
314
+ return b
315
+ }
316
+
317
+ // medianAdjacentOrdered finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
318
+ func medianAdjacentOrdered[E cmp.Ordered](data []E, a int, swaps *int) int {
319
+ return medianOrdered(data, a-1, a, a+1, swaps)
320
+ }
321
+
322
+ func reverseRangeOrdered[E cmp.Ordered](data []E, a, b int) {
323
+ i := a
324
+ j := b - 1
325
+ for i < j {
326
+ data[i], data[j] = data[j], data[i]
327
+ i++
328
+ j--
329
+ }
330
+ }
331
+
332
+ func swapRangeOrdered[E cmp.Ordered](data []E, a, b, n int) {
333
+ for i := 0; i < n; i++ {
334
+ data[a+i], data[b+i] = data[b+i], data[a+i]
335
+ }
336
+ }
337
+
338
+ func stableOrdered[E cmp.Ordered](data []E, n int) {
339
+ blockSize := 20 // must be > 0
340
+ a, b := 0, blockSize
341
+ for b <= n {
342
+ insertionSortOrdered(data, a, b)
343
+ a = b
344
+ b += blockSize
345
+ }
346
+ insertionSortOrdered(data, a, n)
347
+
348
+ for blockSize < n {
349
+ a, b = 0, 2*blockSize
350
+ for b <= n {
351
+ symMergeOrdered(data, a, a+blockSize, b)
352
+ a = b
353
+ b += 2 * blockSize
354
+ }
355
+ if m := a + blockSize; m < n {
356
+ symMergeOrdered(data, a, m, n)
357
+ }
358
+ blockSize *= 2
359
+ }
360
+ }
361
+
362
+ // symMergeOrdered merges the two sorted subsequences data[a:m] and data[m:b] using
363
+ // the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
364
+ // Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
365
+ // Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
366
+ // Computer Science, pages 714-723. Springer, 2004.
367
+ //
368
+ // Let M = m-a and N = b-n. Wolog M < N.
369
+ // The recursion depth is bound by ceil(log(N+M)).
370
+ // The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
371
+ // The algorithm needs O((M+N)*log(M)) calls to data.Swap.
372
+ //
373
+ // The paper gives O((M+N)*log(M)) as the number of assignments assuming a
374
+ // rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
375
+ // in the paper carries through for Swap operations, especially as the block
376
+ // swapping rotate uses only O(M+N) Swaps.
377
+ //
378
+ // symMerge assumes non-degenerate arguments: a < m && m < b.
379
+ // Having the caller check this condition eliminates many leaf recursion calls,
380
+ // which improves performance.
381
+ func symMergeOrdered[E cmp.Ordered](data []E, a, m, b int) {
382
+ // Avoid unnecessary recursions of symMerge
383
+ // by direct insertion of data[a] into data[m:b]
384
+ // if data[a:m] only contains one element.
385
+ if m-a == 1 {
386
+ // Use binary search to find the lowest index i
387
+ // such that data[i] >= data[a] for m <= i < b.
388
+ // Exit the search loop with i == b in case no such index exists.
389
+ i := m
390
+ j := b
391
+ for i < j {
392
+ h := int(uint(i+j) >> 1)
393
+ if cmp.Less(data[h], data[a]) {
394
+ i = h + 1
395
+ } else {
396
+ j = h
397
+ }
398
+ }
399
+ // Swap values until data[a] reaches the position before i.
400
+ for k := a; k < i-1; k++ {
401
+ data[k], data[k+1] = data[k+1], data[k]
402
+ }
403
+ return
404
+ }
405
+
406
+ // Avoid unnecessary recursions of symMerge
407
+ // by direct insertion of data[m] into data[a:m]
408
+ // if data[m:b] only contains one element.
409
+ if b-m == 1 {
410
+ // Use binary search to find the lowest index i
411
+ // such that data[i] > data[m] for a <= i < m.
412
+ // Exit the search loop with i == m in case no such index exists.
413
+ i := a
414
+ j := m
415
+ for i < j {
416
+ h := int(uint(i+j) >> 1)
417
+ if !cmp.Less(data[m], data[h]) {
418
+ i = h + 1
419
+ } else {
420
+ j = h
421
+ }
422
+ }
423
+ // Swap values until data[m] reaches the position i.
424
+ for k := m; k > i; k-- {
425
+ data[k], data[k-1] = data[k-1], data[k]
426
+ }
427
+ return
428
+ }
429
+
430
+ mid := int(uint(a+b) >> 1)
431
+ n := mid + m
432
+ var start, r int
433
+ if m > mid {
434
+ start = n - b
435
+ r = mid
436
+ } else {
437
+ start = a
438
+ r = m
439
+ }
440
+ p := n - 1
441
+
442
+ for start < r {
443
+ c := int(uint(start+r) >> 1)
444
+ if !cmp.Less(data[p-c], data[c]) {
445
+ start = c + 1
446
+ } else {
447
+ r = c
448
+ }
449
+ }
450
+
451
+ end := n - start
452
+ if start < m && m < end {
453
+ rotateOrdered(data, start, m, end)
454
+ }
455
+ if a < start && start < mid {
456
+ symMergeOrdered(data, a, start, mid)
457
+ }
458
+ if mid < end && end < b {
459
+ symMergeOrdered(data, mid, end, b)
460
+ }
461
+ }
462
+
463
+ // rotateOrdered rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
464
+ // Data of the form 'x u v y' is changed to 'x v u y'.
465
+ // rotate performs at most b-a many calls to data.Swap,
466
+ // and it assumes non-degenerate arguments: a < m && m < b.
467
+ func rotateOrdered[E cmp.Ordered](data []E, a, m, b int) {
468
+ i := m - a
469
+ j := b - m
470
+
471
+ for i != j {
472
+ if i > j {
473
+ swapRangeOrdered(data, m-i, m, j)
474
+ i -= j
475
+ } else {
476
+ swapRangeOrdered(data, m-i, m+j-i, i)
477
+ j -= i
478
+ }
479
+ }
480
+ // i == j
481
+ swapRangeOrdered(data, m-i, m, i)
482
+ }