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,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 sort
8
+
9
+ // insertionSort sorts data[a:b] using insertion sort.
10
+ func insertionSort(data Interface, a, b int) {
11
+ for i := a + 1; i < b; i++ {
12
+ for j := i; j > a && data.Less(j, j-1); j-- {
13
+ data.Swap(j, j-1)
14
+ }
15
+ }
16
+ }
17
+
18
+ // siftDown 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 siftDown(data Interface, lo, hi, first int) {
21
+ root := lo
22
+ for {
23
+ child := 2*root + 1
24
+ if child >= hi {
25
+ break
26
+ }
27
+ if child+1 < hi && data.Less(first+child, first+child+1) {
28
+ child++
29
+ }
30
+ if !data.Less(first+root, first+child) {
31
+ return
32
+ }
33
+ data.Swap(first+root, first+child)
34
+ root = child
35
+ }
36
+ }
37
+
38
+ func heapSort(data Interface, a, b 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
+ siftDown(data, i, hi, first)
46
+ }
47
+
48
+ // Pop elements, largest first, into end of data.
49
+ for i := hi - 1; i >= 0; i-- {
50
+ data.Swap(first, first+i)
51
+ siftDown(data, lo, i, first)
52
+ }
53
+ }
54
+
55
+ // pdqsort 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 pdqsort(data Interface, a, b, limit 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
+ insertionSort(data, a, b)
74
+ return
75
+ }
76
+
77
+ // Fall back to heapsort if too many bad choices were made.
78
+ if limit == 0 {
79
+ heapSort(data, a, b)
80
+ return
81
+ }
82
+
83
+ // If the last partitioning was imbalanced, we need to breaking patterns.
84
+ if !wasBalanced {
85
+ breakPatterns(data, a, b)
86
+ limit--
87
+ }
88
+
89
+ pivot, hint := choosePivot(data, a, b)
90
+ if hint == decreasingHint {
91
+ reverseRange(data, a, b)
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 partialInsertionSort(data, a, b) {
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 && !data.Less(a-1, pivot) {
109
+ mid := partitionEqual(data, a, b, pivot)
110
+ a = mid
111
+ continue
112
+ }
113
+
114
+ mid, alreadyPartitioned := partition(data, a, b, pivot)
115
+ wasPartitioned = alreadyPartitioned
116
+
117
+ leftLen, rightLen := mid-a, b-mid
118
+ balanceThreshold := length / 8
119
+ if leftLen < rightLen {
120
+ wasBalanced = leftLen >= balanceThreshold
121
+ pdqsort(data, a, mid, limit)
122
+ a = mid + 1
123
+ } else {
124
+ wasBalanced = rightLen >= balanceThreshold
125
+ pdqsort(data, mid+1, b, limit)
126
+ b = mid
127
+ }
128
+ }
129
+ }
130
+
131
+ // partition 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 partition(data Interface, a, b, pivot int) (newpivot int, alreadyPartitioned bool) {
136
+ data.Swap(a, pivot)
137
+ i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
138
+
139
+ for i <= j && data.Less(i, a) {
140
+ i++
141
+ }
142
+ for i <= j && !data.Less(j, a) {
143
+ j--
144
+ }
145
+ if i > j {
146
+ data.Swap(j, a)
147
+ return j, true
148
+ }
149
+ data.Swap(i, j)
150
+ i++
151
+ j--
152
+
153
+ for {
154
+ for i <= j && data.Less(i, a) {
155
+ i++
156
+ }
157
+ for i <= j && !data.Less(j, a) {
158
+ j--
159
+ }
160
+ if i > j {
161
+ break
162
+ }
163
+ data.Swap(i, j)
164
+ i++
165
+ j--
166
+ }
167
+ data.Swap(j, a)
168
+ return j, false
169
+ }
170
+
171
+ // partitionEqual 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 partitionEqual(data Interface, a, b, pivot int) (newpivot int) {
174
+ data.Swap(a, pivot)
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 && !data.Less(a, i) {
179
+ i++
180
+ }
181
+ for i <= j && data.Less(a, j) {
182
+ j--
183
+ }
184
+ if i > j {
185
+ break
186
+ }
187
+ data.Swap(i, j)
188
+ i++
189
+ j--
190
+ }
191
+ return i
192
+ }
193
+
194
+ // partialInsertionSort partially sorts a slice, returns true if the slice is sorted at the end.
195
+ func partialInsertionSort(data Interface, a, b 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 && !data.Less(i, i-1) {
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.Swap(i, i-1)
215
+
216
+ // Shift the smaller one to the left.
217
+ if i-a >= 2 {
218
+ for j := i - 1; j >= 1; j-- {
219
+ if !data.Less(j, j-1) {
220
+ break
221
+ }
222
+ data.Swap(j, j-1)
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 !data.Less(j, j-1) {
229
+ break
230
+ }
231
+ data.Swap(j, j-1)
232
+ }
233
+ }
234
+ }
235
+ return false
236
+ }
237
+
238
+ // breakPatterns scatters some elements around in an attempt to break some patterns
239
+ // that might cause imbalanced partitions in quicksort.
240
+ func breakPatterns(data Interface, a, b 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.Swap(idx, a+other)
253
+ }
254
+ }
255
+ }
256
+
257
+ // choosePivot 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 choosePivot(data Interface, a, b 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 = medianAdjacent(data, i, &swaps)
281
+ j = medianAdjacent(data, j, &swaps)
282
+ k = medianAdjacent(data, k, &swaps)
283
+ }
284
+ // Find the median among i, j, k and stores it into j.
285
+ j = median(data, i, j, k, &swaps)
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
+ // order2 returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
299
+ func order2(data Interface, a, b int, swaps *int) (int, int) {
300
+ if data.Less(b, a) {
301
+ *swaps++
302
+ return b, a
303
+ }
304
+ return a, b
305
+ }
306
+
307
+ // median returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
308
+ func median(data Interface, a, b, c int, swaps *int) int {
309
+ a, b = order2(data, a, b, swaps)
310
+ b, c = order2(data, b, c, swaps)
311
+ a, b = order2(data, a, b, swaps)
312
+ return b
313
+ }
314
+
315
+ // medianAdjacent finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
316
+ func medianAdjacent(data Interface, a int, swaps *int) int {
317
+ return median(data, a-1, a, a+1, swaps)
318
+ }
319
+
320
+ func reverseRange(data Interface, a, b int) {
321
+ i := a
322
+ j := b - 1
323
+ for i < j {
324
+ data.Swap(i, j)
325
+ i++
326
+ j--
327
+ }
328
+ }
329
+
330
+ func swapRange(data Interface, a, b, n int) {
331
+ for i := 0; i < n; i++ {
332
+ data.Swap(a+i, b+i)
333
+ }
334
+ }
335
+
336
+ func stable(data Interface, n int) {
337
+ blockSize := 20 // must be > 0
338
+ a, b := 0, blockSize
339
+ for b <= n {
340
+ insertionSort(data, a, b)
341
+ a = b
342
+ b += blockSize
343
+ }
344
+ insertionSort(data, a, n)
345
+
346
+ for blockSize < n {
347
+ a, b = 0, 2*blockSize
348
+ for b <= n {
349
+ symMerge(data, a, a+blockSize, b)
350
+ a = b
351
+ b += 2 * blockSize
352
+ }
353
+ if m := a + blockSize; m < n {
354
+ symMerge(data, a, m, n)
355
+ }
356
+ blockSize *= 2
357
+ }
358
+ }
359
+
360
+ // symMerge 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 symMerge(data Interface, a, m, b 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 data.Less(h, a) {
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.Swap(k, k+1)
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 !data.Less(m, h) {
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.Swap(k, k-1)
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 !data.Less(p-c, c) {
443
+ start = c + 1
444
+ } else {
445
+ r = c
446
+ }
447
+ }
448
+
449
+ end := n - start
450
+ if start < m && m < end {
451
+ rotate(data, start, m, end)
452
+ }
453
+ if a < start && start < mid {
454
+ symMerge(data, a, start, mid)
455
+ }
456
+ if mid < end && end < b {
457
+ symMerge(data, mid, end, b)
458
+ }
459
+ }
460
+
461
+ // rotate 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 rotate(data Interface, a, m, b int) {
466
+ i := m - a
467
+ j := b - m
468
+
469
+ for i != j {
470
+ if i > j {
471
+ swapRange(data, m-i, m, j)
472
+ i -= j
473
+ } else {
474
+ swapRange(data, m-i, m+j-i, i)
475
+ j -= i
476
+ }
477
+ }
478
+ // i == j
479
+ swapRange(data, m-i, m, i)
480
+ }