goscript 0.1.1 → 0.1.2
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/cmd/goscript/cmd-test.go +104 -11
- package/cmd/goscript/cmd-test_test.go +1 -1
- package/cmd/goscript/cmd_compile.go +9 -0
- package/compiler/compile-request.go +31 -0
- package/compiler/compiler.go +1 -1
- package/compiler/compliance_test.go +0 -2
- package/compiler/config.go +2 -0
- package/compiler/gotest/package-result.go +2 -0
- package/compiler/gotest/request.go +85 -20
- package/compiler/gotest/runner.go +733 -96
- package/compiler/gotest/runner_test.go +647 -3
- package/compiler/lowered-program.go +9 -2
- package/compiler/lowering.go +2001 -345
- package/compiler/override-facts.go +77 -27
- package/compiler/override-registry.go +5 -4
- package/compiler/override-registry_test.go +135 -0
- package/compiler/package-graph_test.go +62 -7
- package/compiler/package-test-graph-variant.go +40 -16
- package/compiler/package-test-graph.go +0 -5
- package/compiler/package-test-graph_test.go +61 -3
- package/compiler/runtime-contract.go +40 -0
- package/compiler/semantic-model-types.go +16 -0
- package/compiler/semantic-model.go +336 -91
- package/compiler/semantic-model_test.go +50 -1
- package/compiler/service.go +9 -3
- package/compiler/skeleton_test.go +1921 -298
- package/compiler/tsworkspace/owner-process-unix_test.go +72 -0
- package/compiler/tsworkspace/owner.go +8 -0
- package/compiler/tsworkspace/tool-process-other.go +14 -0
- package/compiler/tsworkspace/tool-process-unix.go +19 -0
- package/compiler/typescript-emitter.go +122 -9
- package/dist/gs/builtin/builtin.d.ts +20 -1
- package/dist/gs/builtin/builtin.js +246 -26
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +24 -10
- package/dist/gs/builtin/channel.js +107 -25
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/defer.d.ts +1 -0
- package/dist/gs/builtin/defer.js +12 -2
- package/dist/gs/builtin/defer.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +9 -0
- package/dist/gs/builtin/hostio.js +25 -0
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/map.js +40 -6
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/print.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +43 -9
- package/dist/gs/builtin/slice.js +437 -234
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +2 -0
- package/dist/gs/builtin/type.js +47 -7
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +2 -0
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js +28 -28
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/iter.gs.js +13 -13
- package/dist/gs/bytes/iter.gs.js.map +1 -1
- package/dist/gs/compress/zlib/index.d.ts +26 -0
- package/dist/gs/compress/zlib/index.js +168 -0
- package/dist/gs/compress/zlib/index.js.map +1 -0
- package/dist/gs/context/context.d.ts +1 -1
- package/dist/gs/context/context.js +8 -3
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/ecdh/index.d.ts +52 -0
- package/dist/gs/crypto/ecdh/index.js +226 -0
- package/dist/gs/crypto/ecdh/index.js.map +1 -0
- package/dist/gs/crypto/ed25519/index.d.ts +34 -0
- package/dist/gs/crypto/ed25519/index.js +160 -0
- package/dist/gs/crypto/ed25519/index.js.map +1 -0
- package/dist/gs/crypto/internal/constanttime/index.d.ts +4 -0
- package/dist/gs/crypto/internal/constanttime/index.js +18 -0
- package/dist/gs/crypto/internal/constanttime/index.js.map +1 -0
- package/dist/gs/crypto/rand/index.d.ts +2 -0
- package/dist/gs/crypto/rand/index.js +85 -0
- package/dist/gs/crypto/rand/index.js.map +1 -1
- package/dist/gs/crypto/sha256/index.d.ts +8 -0
- package/dist/gs/crypto/sha256/index.js +118 -0
- package/dist/gs/crypto/sha256/index.js.map +1 -0
- package/dist/gs/crypto/sha512/index.d.ts +14 -0
- package/dist/gs/crypto/sha512/index.js +129 -0
- package/dist/gs/crypto/sha512/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +15 -0
- package/dist/gs/encoding/json/index.js.map +1 -1
- package/dist/gs/errors/errors.js +29 -6
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +7 -7
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +52 -18
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +56 -20
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +57 -3
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +366 -1
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +20 -0
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js +134 -0
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +1 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.d.ts +3 -0
- package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js +50 -0
- package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js.map +1 -0
- package/dist/gs/github.com/klauspost/compress/internal/le/index.js +3 -2
- package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.d.ts +27 -0
- package/dist/gs/github.com/mr-tron/base58/base58/index.js +172 -0
- package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -0
- package/dist/gs/github.com/zeebo/blake3/internal/consts/index.d.ts +21 -0
- package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js +22 -0
- package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js.map +1 -0
- package/dist/gs/go/token/index.js +11 -4
- package/dist/gs/go/token/index.js.map +1 -1
- package/dist/gs/hash/fnv/index.d.ts +57 -0
- package/dist/gs/hash/fnv/index.js +299 -0
- package/dist/gs/hash/fnv/index.js.map +1 -0
- package/dist/gs/hash/index.d.ts +17 -0
- package/dist/gs/hash/index.js +94 -0
- package/dist/gs/hash/index.js.map +1 -0
- package/dist/gs/io/fs/readlink.js +2 -6
- package/dist/gs/io/fs/readlink.js.map +1 -1
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/iter/iter.d.ts +3 -2
- package/dist/gs/iter/iter.js.map +1 -1
- package/dist/gs/maps/iter.d.ts +5 -5
- package/dist/gs/maps/iter.js +48 -21
- package/dist/gs/maps/iter.js.map +1 -1
- package/dist/gs/maps/maps.d.ts +6 -6
- package/dist/gs/math/bits/index.js +14 -24
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/mime/index.js +3 -1
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.d.ts +20 -1
- package/dist/gs/net/http/httptest/index.js +83 -3
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +110 -6
- package/dist/gs/net/http/index.js +262 -16
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/net/http/pprof/index.d.ts +8 -0
- package/dist/gs/net/http/pprof/index.js +59 -0
- package/dist/gs/net/http/pprof/index.js.map +1 -0
- package/dist/gs/os/error.gs.js +9 -7
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.js +95 -15
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/filepath/path.d.ts +5 -3
- package/dist/gs/path/filepath/path.js +65 -10
- package/dist/gs/path/filepath/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +3 -2
- package/dist/gs/reflect/index.js +2 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/iter.js +2 -2
- package/dist/gs/reflect/iter.js.map +1 -1
- package/dist/gs/reflect/map.js +26 -0
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +24 -5
- package/dist/gs/reflect/type.js +390 -38
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.d.ts +1 -0
- package/dist/gs/reflect/types.js +3 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/value.d.ts +4 -1
- package/dist/gs/reflect/value.js +39 -1
- package/dist/gs/reflect/value.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/debug/index.d.ts +39 -0
- package/dist/gs/runtime/debug/index.js +58 -0
- package/dist/gs/runtime/debug/index.js.map +1 -1
- package/dist/gs/runtime/pprof/index.d.ts +20 -0
- package/dist/gs/runtime/pprof/index.js +85 -0
- package/dist/gs/runtime/pprof/index.js.map +1 -0
- package/dist/gs/runtime/trace/index.d.ts +19 -0
- package/dist/gs/runtime/trace/index.js +64 -0
- package/dist/gs/runtime/trace/index.js.map +1 -0
- package/dist/gs/slices/slices.d.ts +24 -9
- package/dist/gs/slices/slices.js +229 -24
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/sort/slice.gs.d.ts +5 -3
- package/dist/gs/sort/slice.gs.js +55 -17
- package/dist/gs/sort/slice.gs.js.map +1 -1
- package/dist/gs/strings/builder.js +26 -17
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/iter.js +140 -75
- package/dist/gs/strings/iter.js.map +1 -1
- package/dist/gs/strings/replace.js +2 -2
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/strings/strings.js +52 -6
- package/dist/gs/strings/strings.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +6 -3
- package/dist/gs/sync/sync.js +39 -11
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/syscall/errors.d.ts +116 -112
- package/dist/gs/syscall/errors.js +38 -1
- package/dist/gs/syscall/errors.js.map +1 -1
- package/dist/gs/syscall/fs.d.ts +2 -8
- package/dist/gs/syscall/fs.js.map +1 -1
- package/dist/gs/syscall/js/index.js +20 -12
- package/dist/gs/syscall/js/index.js.map +1 -1
- package/dist/gs/syscall/types.d.ts +4 -1
- package/dist/gs/syscall/types.js.map +1 -1
- package/dist/gs/testing/testing.d.ts +4 -3
- package/dist/gs/testing/testing.js +21 -4
- package/dist/gs/testing/testing.js.map +1 -1
- package/dist/gs/time/time.js +22 -0
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/dist/gs/unique/index.js +7 -2
- package/dist/gs/unique/index.js.map +1 -1
- package/go.mod +8 -8
- package/go.sum +14 -23
- package/gs/builtin/builtin.ts +364 -37
- package/gs/builtin/channel.ts +161 -29
- package/gs/builtin/defer.ts +13 -2
- package/gs/builtin/hostio.test.ts +1 -0
- package/gs/builtin/hostio.ts +38 -0
- package/gs/builtin/map.ts +46 -6
- package/gs/builtin/print.ts +12 -3
- package/gs/builtin/runtime-contract.test.ts +257 -10
- package/gs/builtin/slice.test.ts +70 -0
- package/gs/builtin/slice.ts +566 -255
- package/gs/builtin/type.ts +53 -9
- package/gs/builtin/varRef.ts +2 -0
- package/gs/bytes/buffer.gs.ts +28 -28
- package/gs/bytes/iter.gs.ts +13 -14
- package/gs/compress/zlib/index.test.ts +28 -0
- package/gs/compress/zlib/index.ts +200 -0
- package/gs/compress/zlib/meta.json +3 -0
- package/gs/context/context.test.ts +31 -1
- package/gs/context/context.ts +9 -4
- package/gs/crypto/ecdh/index.test.ts +43 -0
- package/gs/crypto/ecdh/index.ts +274 -0
- package/gs/crypto/ed25519/index.test.ts +41 -0
- package/gs/crypto/ed25519/index.ts +238 -0
- package/gs/crypto/ed25519/meta.json +13 -0
- package/gs/crypto/internal/constanttime/index.test.ts +25 -0
- package/gs/crypto/internal/constanttime/index.ts +22 -0
- package/gs/crypto/rand/index.test.ts +89 -1
- package/gs/crypto/rand/index.ts +103 -1
- package/gs/crypto/rand/meta.json +4 -1
- package/gs/crypto/sha256/index.test.ts +78 -0
- package/gs/crypto/sha256/index.ts +150 -0
- package/gs/crypto/sha256/meta.json +9 -0
- package/gs/crypto/sha512/index.test.ts +31 -0
- package/gs/crypto/sha512/index.ts +161 -0
- package/gs/crypto/sha512/meta.json +11 -0
- package/gs/encoding/json/index.test.ts +25 -3
- package/gs/encoding/json/index.ts +21 -3
- package/gs/errors/errors.test.ts +4 -1
- package/gs/errors/errors.ts +32 -8
- package/gs/fmt/fmt.test.ts +3 -1
- package/gs/fmt/fmt.ts +1 -5
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +62 -7
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +78 -36
- package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +32 -11
- package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +122 -43
- package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +31 -0
- package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +518 -4
- package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +6 -0
- package/gs/github.com/aperturerobotics/util/conc/index.test.ts +30 -0
- package/gs/github.com/aperturerobotics/util/conc/index.ts +172 -0
- package/gs/github.com/aperturerobotics/util/conc/meta.json +9 -0
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.ts +1 -4
- package/gs/github.com/hack-pad/safejs/internal/catch/index.test.ts +35 -0
- package/gs/github.com/hack-pad/safejs/internal/catch/index.ts +65 -0
- package/gs/github.com/hack-pad/safejs/internal/catch/meta.json +9 -0
- package/gs/github.com/klauspost/compress/internal/le/index.test.ts +2 -1
- package/gs/github.com/klauspost/compress/internal/le/index.ts +6 -5
- package/gs/github.com/mr-tron/base58/base58/index.test.ts +70 -0
- package/gs/github.com/mr-tron/base58/base58/index.ts +231 -0
- package/gs/github.com/mr-tron/base58/base58/meta.json +3 -0
- package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +46 -0
- package/gs/github.com/zeebo/blake3/internal/consts/index.ts +26 -0
- package/gs/go/token/index.ts +17 -4
- package/gs/hash/fnv/index.test.ts +67 -0
- package/gs/hash/fnv/index.ts +351 -0
- package/gs/hash/fnv/meta.json +3 -0
- package/gs/hash/index.test.ts +37 -0
- package/gs/hash/index.ts +118 -0
- package/gs/hash/meta.json +5 -0
- package/gs/internal/byteorder/index.test.ts +6 -6
- package/gs/io/fs/readlink.ts +40 -48
- package/gs/io/fs/walk.ts +10 -2
- package/gs/io/io.ts +4 -1
- package/gs/iter/iter.ts +8 -2
- package/gs/maps/iter.ts +69 -26
- package/gs/maps/maps.test.ts +23 -0
- package/gs/maps/maps.ts +6 -6
- package/gs/math/bits/index.test.ts +20 -0
- package/gs/math/bits/index.ts +15 -28
- package/gs/mime/index.ts +8 -2
- package/gs/net/http/httptest/index.test.ts +53 -0
- package/gs/net/http/httptest/index.ts +98 -3
- package/gs/net/http/index.test.ts +129 -1
- package/gs/net/http/index.ts +370 -19
- package/gs/net/http/meta.json +6 -0
- package/gs/net/http/pprof/index.test.ts +47 -0
- package/gs/net/http/pprof/index.ts +65 -0
- package/gs/os/error.gs.ts +9 -10
- package/gs/os/error.test.ts +41 -0
- package/gs/os/file_unix_js.test.ts +55 -0
- package/gs/os/tempfile.gs.test.ts +37 -10
- package/gs/os/types_js.gs.ts +94 -15
- package/gs/path/filepath/match.ts +4 -1
- package/gs/path/filepath/meta.json +6 -0
- package/gs/path/filepath/path.test.ts +57 -2
- package/gs/path/filepath/path.ts +91 -12
- package/gs/reflect/field.test.ts +63 -0
- package/gs/reflect/index.ts +4 -1
- package/gs/reflect/iter.ts +2 -2
- package/gs/reflect/map.test.ts +24 -2
- package/gs/reflect/map.ts +35 -0
- package/gs/reflect/type.ts +543 -60
- package/gs/reflect/typefor.test.ts +100 -0
- package/gs/reflect/types.ts +3 -1
- package/gs/reflect/value.ts +50 -1
- package/gs/reflect/visiblefields.ts +1 -1
- package/gs/runtime/debug/index.test.ts +22 -1
- package/gs/runtime/debug/index.ts +88 -0
- package/gs/runtime/pprof/index.test.ts +36 -0
- package/gs/runtime/pprof/index.ts +104 -0
- package/gs/runtime/pprof/meta.json +6 -0
- package/gs/runtime/trace/index.test.ts +45 -0
- package/gs/runtime/trace/index.ts +97 -0
- package/gs/runtime/trace/meta.json +7 -0
- package/gs/slices/meta.json +2 -1
- package/gs/slices/slices.test.ts +86 -0
- package/gs/slices/slices.ts +284 -37
- package/gs/sort/slice.gs.ts +73 -23
- package/gs/sort/slice.test.ts +40 -0
- package/gs/strings/builder.test.ts +8 -0
- package/gs/strings/builder.ts +29 -17
- package/gs/strings/iter.test.ts +5 -7
- package/gs/strings/iter.ts +146 -71
- package/gs/strings/replace.test.ts +1 -4
- package/gs/strings/replace.ts +6 -6
- package/gs/strings/strings.test.ts +4 -0
- package/gs/strings/strings.ts +54 -6
- package/gs/sync/sync.test.ts +57 -1
- package/gs/sync/sync.ts +45 -13
- package/gs/syscall/errors.ts +158 -115
- package/gs/syscall/fs.ts +8 -8
- package/gs/syscall/js/index.ts +49 -22
- package/gs/syscall/net.test.ts +26 -0
- package/gs/syscall/types.ts +7 -2
- package/gs/testing/testing.test.ts +56 -0
- package/gs/testing/testing.ts +27 -10
- package/gs/time/meta.json +2 -2
- package/gs/time/time.test.ts +4 -0
- package/gs/time/time.ts +33 -2
- package/gs/unicode/unicode.test.ts +14 -3
- package/gs/unicode/unicode.ts +1 -5
- package/gs/unique/index.ts +9 -2
- package/package.json +3 -3
package/gs/slices/slices.test.ts
CHANGED
|
@@ -3,10 +3,24 @@ import { describe, expect, it } from 'vitest'
|
|
|
3
3
|
import * as $ from '@goscript/builtin/index.js'
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
+
All,
|
|
6
7
|
Backward,
|
|
8
|
+
BinarySearch,
|
|
9
|
+
Clip,
|
|
10
|
+
Compact,
|
|
11
|
+
CompactFunc,
|
|
12
|
+
CompareFunc,
|
|
13
|
+
Concat,
|
|
14
|
+
DeleteFunc,
|
|
15
|
+
EqualFunc,
|
|
16
|
+
IndexFunc,
|
|
7
17
|
IsSorted,
|
|
8
18
|
IsSortedFunc,
|
|
9
19
|
Max,
|
|
20
|
+
MaxFunc,
|
|
21
|
+
Min,
|
|
22
|
+
MinFunc,
|
|
23
|
+
Replace,
|
|
10
24
|
Sorted,
|
|
11
25
|
SortStableFunc,
|
|
12
26
|
} from './slices.js'
|
|
@@ -26,6 +40,63 @@ describe('slices.SortStableFunc', () => {
|
|
|
26
40
|
})
|
|
27
41
|
})
|
|
28
42
|
|
|
43
|
+
describe('slices compatibility helpers', () => {
|
|
44
|
+
it('implements comparison, min/max, compact, replace, clip, and search helpers', () => {
|
|
45
|
+
expect(
|
|
46
|
+
CompareFunc($.arrayToSlice(['a', 'c']), $.arrayToSlice(['a', 'b']), (a, b) =>
|
|
47
|
+
a.localeCompare(b),
|
|
48
|
+
),
|
|
49
|
+
).toBeGreaterThan(0)
|
|
50
|
+
expect(Min($.arrayToSlice([3, 1, 2]))).toBe(1)
|
|
51
|
+
expect(MaxFunc($.arrayToSlice([{ v: 1 }, { v: 4 }]), (a, b) => a.v - b.v).v).toBe(4)
|
|
52
|
+
expect(MinFunc($.arrayToSlice([{ v: 3 }, { v: 2 }]), (a, b) => a.v - b.v).v).toBe(2)
|
|
53
|
+
expect(Array.from(Compact($.arrayToSlice([1, 1, 2, 2, 3])) ?? [])).toEqual([1, 2, 3])
|
|
54
|
+
expect(
|
|
55
|
+
Array.from(
|
|
56
|
+
CompactFunc(
|
|
57
|
+
$.arrayToSlice(['a', 'A', 'b']),
|
|
58
|
+
(a, b) => a.toLowerCase() === b.toLowerCase(),
|
|
59
|
+
) ?? [],
|
|
60
|
+
),
|
|
61
|
+
).toEqual(['a', 'b'])
|
|
62
|
+
expect(Array.from(Replace($.arrayToSlice([1, 2, 3, 4]), 1, 3, 9, 8)) ?? []).toEqual([
|
|
63
|
+
1, 9, 8, 4,
|
|
64
|
+
])
|
|
65
|
+
expect(Array.from(Clip($.arrayToSlice([1, 2])) ?? [])).toEqual([1, 2])
|
|
66
|
+
expect(BinarySearch($.arrayToSlice([1, 3, 5]), 3)).toEqual([1, true])
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('concatenates slices and preserves empty concat nilness', () => {
|
|
70
|
+
expect(Concat()).toBeNull()
|
|
71
|
+
expect(Concat($.arrayToSlice<number>([]))).toBeNull()
|
|
72
|
+
expect(Array.from(Concat($.arrayToSlice([1]), null, $.arrayToSlice([2, 3])) ?? [])).toEqual([
|
|
73
|
+
1, 2, 3,
|
|
74
|
+
])
|
|
75
|
+
expect(Array.from(Concat(new Uint8Array([1, 2]), new Uint8Array([3])) ?? [])).toEqual([
|
|
76
|
+
1, 2, 3,
|
|
77
|
+
])
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('accepts generated possibly-async callback types for sync helpers', () => {
|
|
81
|
+
const compare: (a: number, b: number) => number | Promise<number> = (a, b) => a - b
|
|
82
|
+
const keepOdd: (v: number) => boolean | Promise<boolean> = (v) => v % 2 === 0
|
|
83
|
+
const equal: (a: string, b: string) => boolean | Promise<boolean> = (a, b) => a === b
|
|
84
|
+
|
|
85
|
+
expect(CompareFunc($.arrayToSlice([1]), $.arrayToSlice([2]), compare)).toBeLessThan(0)
|
|
86
|
+
expect(Array.from(DeleteFunc($.arrayToSlice([1, 2, 3]), keepOdd) ?? [])).toEqual([1, 3])
|
|
87
|
+
expect(EqualFunc($.arrayToSlice(['a']), $.arrayToSlice(['a']), equal)).toBe(true)
|
|
88
|
+
expect(IndexFunc($.arrayToSlice([1, 2, 3]), keepOdd)).toBe(1)
|
|
89
|
+
expect(IsSortedFunc($.arrayToSlice([1, 2, 3]), compare)).toBe(true)
|
|
90
|
+
expect(BinarySearch($.arrayToSlice([1, 2, 3]), 2)).toEqual([1, true])
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('rejects actual async callback results in sync helpers', () => {
|
|
94
|
+
expect(() =>
|
|
95
|
+
CompareFunc($.arrayToSlice([1]), $.arrayToSlice([2]), async (a, b) => a - b),
|
|
96
|
+
).toThrow('slices: asynchronous callback result is not supported')
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
|
|
29
100
|
describe('slices.Sorted', () => {
|
|
30
101
|
it('collects and sorts iterator values', () => {
|
|
31
102
|
const values = Sorted<string>((yieldValue) => {
|
|
@@ -67,6 +138,21 @@ describe('slices.Backward', () => {
|
|
|
67
138
|
})
|
|
68
139
|
})
|
|
69
140
|
|
|
141
|
+
describe('slices.All', () => {
|
|
142
|
+
it('accepts async yield callbacks', async () => {
|
|
143
|
+
const visited: Array<[number, string]> = []
|
|
144
|
+
await All($.arrayToSlice(['a', 'b', 'c']))(async (index, value) => {
|
|
145
|
+
visited.push([index, value])
|
|
146
|
+
return index < 1
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
expect(visited).toEqual([
|
|
150
|
+
[0, 'a'],
|
|
151
|
+
[1, 'b'],
|
|
152
|
+
])
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
|
|
70
156
|
describe('slices.IsSorted', () => {
|
|
71
157
|
it('reports ordered and unordered slices', () => {
|
|
72
158
|
expect(IsSorted($.arrayToSlice([1, 2, 3]))).toBe(true)
|
package/gs/slices/slices.ts
CHANGED
|
@@ -3,6 +3,11 @@ import * as $ from '@goscript/builtin/index.js'
|
|
|
3
3
|
import * as cmp from '../cmp/index.js'
|
|
4
4
|
import * as iter from '../iter/index.js'
|
|
5
5
|
|
|
6
|
+
type SyncCallbackResult<T> = T | globalThis.Promise<T>
|
|
7
|
+
type CompareCallback<T, U = T> = ((v1: T, v2: U) => SyncCallbackResult<number>) | null
|
|
8
|
+
type PredicateCallback<T> = ((value: T) => SyncCallbackResult<boolean>) | null
|
|
9
|
+
type EqualCallback<T, U = T> = ((v1: T, v2: U) => SyncCallbackResult<boolean>) | null
|
|
10
|
+
|
|
6
11
|
/**
|
|
7
12
|
* Compare compares the elements of s1 and s2 using cmp.Compare.
|
|
8
13
|
* The elements are compared sequentially, starting at index 0,
|
|
@@ -42,6 +47,34 @@ export function Compare<T extends string | number>(
|
|
|
42
47
|
return 0
|
|
43
48
|
}
|
|
44
49
|
|
|
50
|
+
export function CompareFunc<T, U>(
|
|
51
|
+
s1: $.Slice<T>,
|
|
52
|
+
s2: $.Slice<U>,
|
|
53
|
+
compare: CompareCallback<T, U>,
|
|
54
|
+
): number {
|
|
55
|
+
if (compare == null) {
|
|
56
|
+
throw new Error('slices.CompareFunc: nil comparison function')
|
|
57
|
+
}
|
|
58
|
+
const len1 = $.len(s1)
|
|
59
|
+
const len2 = $.len(s2)
|
|
60
|
+
const minLen = len1 < len2 ? len1 : len2
|
|
61
|
+
for (let i = 0; i < minLen; i++) {
|
|
62
|
+
const result = syncNumber(
|
|
63
|
+
compare((s1 as any)[i] as T, (s2 as any)[i] as U),
|
|
64
|
+
)
|
|
65
|
+
if (result !== 0) {
|
|
66
|
+
return result
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (len1 < len2) {
|
|
70
|
+
return -1
|
|
71
|
+
}
|
|
72
|
+
if (len1 > len2) {
|
|
73
|
+
return 1
|
|
74
|
+
}
|
|
75
|
+
return 0
|
|
76
|
+
}
|
|
77
|
+
|
|
45
78
|
/**
|
|
46
79
|
* Clone returns a shallow copy of s while preserving nilness.
|
|
47
80
|
* @param s The slice to clone
|
|
@@ -58,6 +91,38 @@ export function Clone<T>(s: $.Slice<T>): $.Slice<T> {
|
|
|
58
91
|
return out
|
|
59
92
|
}
|
|
60
93
|
|
|
94
|
+
export function Concat<T>(...slices: $.Slice<T>[]): $.Slice<T> {
|
|
95
|
+
let size = 0
|
|
96
|
+
let byteSlice = false
|
|
97
|
+
for (const slice of slices) {
|
|
98
|
+
size += $.len(slice)
|
|
99
|
+
byteSlice = byteSlice || slice instanceof Uint8Array
|
|
100
|
+
}
|
|
101
|
+
if (size === 0) {
|
|
102
|
+
return null
|
|
103
|
+
}
|
|
104
|
+
if (byteSlice) {
|
|
105
|
+
const out = new Uint8Array(size)
|
|
106
|
+
let pos = 0
|
|
107
|
+
for (const slice of slices) {
|
|
108
|
+
const length = $.len(slice)
|
|
109
|
+
for (let i = 0; i < length; i++) {
|
|
110
|
+
out[pos++] = (slice as any)[i] as number
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return out as $.Slice<T>
|
|
114
|
+
}
|
|
115
|
+
const out = $.makeSlice<T>(size)
|
|
116
|
+
let pos = 0
|
|
117
|
+
for (const slice of slices) {
|
|
118
|
+
const length = $.len(slice)
|
|
119
|
+
for (let i = 0; i < length; i++) {
|
|
120
|
+
;(out as any)[pos++] = (slice as any)[i] as T
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return out
|
|
124
|
+
}
|
|
125
|
+
|
|
61
126
|
/**
|
|
62
127
|
* All returns an iterator over index-value pairs in the slice.
|
|
63
128
|
* This is equivalent to Go's slices.All function.
|
|
@@ -66,22 +131,35 @@ export function Clone<T>(s: $.Slice<T>): $.Slice<T> {
|
|
|
66
131
|
*/
|
|
67
132
|
export function All<T>(
|
|
68
133
|
s: $.Slice<T>,
|
|
69
|
-
): (yieldFunc: (index: number, value: T) =>
|
|
70
|
-
return function (
|
|
134
|
+
): (yieldFunc: (index: number, value: T) => iter.YieldResult) => void | globalThis.Promise<void> {
|
|
135
|
+
return function (
|
|
136
|
+
_yield: (index: number, value: T) => iter.YieldResult,
|
|
137
|
+
): void | globalThis.Promise<void> {
|
|
71
138
|
const length = $.len(s)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
139
|
+
const walk = (i: number): void | globalThis.Promise<void> => {
|
|
140
|
+
for (; i < length; i++) {
|
|
141
|
+
const value = (s as any)[i] as T // Use proper indexing to avoid type issues
|
|
142
|
+
const keepGoing = _yield(i, value)
|
|
143
|
+
if (keepGoing instanceof Promise) {
|
|
144
|
+
return keepGoing.then((next) => {
|
|
145
|
+
if (next) {
|
|
146
|
+
return walk(i + 1)
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
if (!keepGoing) {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
76
153
|
}
|
|
77
154
|
}
|
|
155
|
+
return walk(0)
|
|
78
156
|
}
|
|
79
157
|
}
|
|
80
158
|
|
|
81
159
|
export function Backward<T>(
|
|
82
160
|
s: $.Slice<T>,
|
|
83
161
|
): (
|
|
84
|
-
_yield: (index: number, value: T) => boolean | globalThis.Promise<boolean
|
|
162
|
+
_yield: (index: number, value: T) => boolean | globalThis.Promise<boolean>,
|
|
85
163
|
) => void | globalThis.Promise<void> {
|
|
86
164
|
return function (
|
|
87
165
|
_yield: (index: number, value: T) => boolean | globalThis.Promise<boolean>,
|
|
@@ -136,17 +214,73 @@ export function Max<T extends cmp.Ordered>(x: $.Slice<T>): T {
|
|
|
136
214
|
return max
|
|
137
215
|
}
|
|
138
216
|
|
|
217
|
+
export function Min<T extends cmp.Ordered>(x: $.Slice<T>): T {
|
|
218
|
+
if ($.len(x) === 0) {
|
|
219
|
+
throw new Error('slices.Min: empty list')
|
|
220
|
+
}
|
|
221
|
+
let min = (x as any)[0] as T
|
|
222
|
+
for (let i = 1; i < $.len(x); i++) {
|
|
223
|
+
const value = (x as any)[i] as T
|
|
224
|
+
if (cmp.Compare(value, min) < 0) {
|
|
225
|
+
min = value
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return min
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function MaxFunc<T>(
|
|
232
|
+
x: $.Slice<T>,
|
|
233
|
+
compare: CompareCallback<T>,
|
|
234
|
+
): T {
|
|
235
|
+
if (compare == null) {
|
|
236
|
+
throw new Error('slices.MaxFunc: nil comparison function')
|
|
237
|
+
}
|
|
238
|
+
if ($.len(x) === 0) {
|
|
239
|
+
throw new Error('slices.MaxFunc: empty list')
|
|
240
|
+
}
|
|
241
|
+
let max = (x as any)[0] as T
|
|
242
|
+
for (let i = 1; i < $.len(x); i++) {
|
|
243
|
+
const value = (x as any)[i] as T
|
|
244
|
+
if (syncNumber(compare(max, value)) < 0) {
|
|
245
|
+
max = value
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return max
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function MinFunc<T>(
|
|
252
|
+
x: $.Slice<T>,
|
|
253
|
+
compare: CompareCallback<T>,
|
|
254
|
+
): T {
|
|
255
|
+
if (compare == null) {
|
|
256
|
+
throw new Error('slices.MinFunc: nil comparison function')
|
|
257
|
+
}
|
|
258
|
+
if ($.len(x) === 0) {
|
|
259
|
+
throw new Error('slices.MinFunc: empty list')
|
|
260
|
+
}
|
|
261
|
+
let min = (x as any)[0] as T
|
|
262
|
+
for (let i = 1; i < $.len(x); i++) {
|
|
263
|
+
const value = (x as any)[i] as T
|
|
264
|
+
if (syncNumber(compare(value, min)) < 0) {
|
|
265
|
+
min = value
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return min
|
|
269
|
+
}
|
|
270
|
+
|
|
139
271
|
export function Collect<T>(seq: iter.Seq<T>): $.Slice<T> {
|
|
140
272
|
const out: T[] = []
|
|
141
|
-
seq((value) => {
|
|
273
|
+
seq((value: T) => {
|
|
142
274
|
out.push(value)
|
|
143
275
|
return true
|
|
144
276
|
})
|
|
145
277
|
return out.length === 0 ? null : out
|
|
146
278
|
}
|
|
147
279
|
|
|
148
|
-
export function Sorted<T extends string | number>(
|
|
149
|
-
|
|
280
|
+
export function Sorted<T extends string | number>(
|
|
281
|
+
seq: iter.Seq<T>,
|
|
282
|
+
): $.Slice<T> {
|
|
283
|
+
const out = Collect<T>(seq)
|
|
150
284
|
Sort(out)
|
|
151
285
|
return out
|
|
152
286
|
}
|
|
@@ -185,15 +319,18 @@ export function Delete<T>(s: $.Slice<T>, i: number, j: number): $.Slice<T> {
|
|
|
185
319
|
|
|
186
320
|
export function DeleteFunc<T>(
|
|
187
321
|
s: $.Slice<T>,
|
|
188
|
-
del:
|
|
322
|
+
del: PredicateCallback<T>,
|
|
189
323
|
): $.Slice<T> {
|
|
324
|
+
if (del == null) {
|
|
325
|
+
throw new Error('slices.DeleteFunc: nil delete function')
|
|
326
|
+
}
|
|
190
327
|
if (s === null || s === undefined) {
|
|
191
328
|
return s
|
|
192
329
|
}
|
|
193
330
|
let w = 0
|
|
194
331
|
for (let i = 0; i < s.length; i++) {
|
|
195
332
|
const value = s[i] as T
|
|
196
|
-
if (!del(value)) {
|
|
333
|
+
if (!syncBoolean(del(value))) {
|
|
197
334
|
;(s as any)[w] = value
|
|
198
335
|
w++
|
|
199
336
|
}
|
|
@@ -204,6 +341,83 @@ export function DeleteFunc<T>(
|
|
|
204
341
|
return $.goSlice(s, 0, w) as $.Slice<T>
|
|
205
342
|
}
|
|
206
343
|
|
|
344
|
+
export function Replace<T>(
|
|
345
|
+
s: $.Slice<T>,
|
|
346
|
+
i: number,
|
|
347
|
+
j: number,
|
|
348
|
+
...v: T[]
|
|
349
|
+
): $.Slice<T> {
|
|
350
|
+
const length = $.len(s)
|
|
351
|
+
if (i < 0 || j < i || j > length) {
|
|
352
|
+
throw new Error(
|
|
353
|
+
`slice bounds out of range [${i}:${j}] with length ${length}`,
|
|
354
|
+
)
|
|
355
|
+
}
|
|
356
|
+
const out = $.makeSlice<T>(length - (j - i) + v.length)
|
|
357
|
+
let pos = 0
|
|
358
|
+
for (let idx = 0; idx < i; idx++) {
|
|
359
|
+
;(out as any)[pos++] = (s as any)[idx]
|
|
360
|
+
}
|
|
361
|
+
for (const value of v) {
|
|
362
|
+
;(out as any)[pos++] = value
|
|
363
|
+
}
|
|
364
|
+
for (let idx = j; idx < length; idx++) {
|
|
365
|
+
;(out as any)[pos++] = (s as any)[idx]
|
|
366
|
+
}
|
|
367
|
+
return out
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function Compact<T>(s: $.Slice<T>): $.Slice<T> {
|
|
371
|
+
if (s === null || s === undefined || $.len(s) < 2) {
|
|
372
|
+
return s
|
|
373
|
+
}
|
|
374
|
+
let w = 1
|
|
375
|
+
for (let i = 1; i < $.len(s); i++) {
|
|
376
|
+
if ((s as any)[i] !== (s as any)[i - 1]) {
|
|
377
|
+
;(s as any)[w] = (s as any)[i]
|
|
378
|
+
w++
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
for (let i = w; i < $.len(s); i++) {
|
|
382
|
+
;(s as any)[i] = clearValue(s)
|
|
383
|
+
}
|
|
384
|
+
return $.goSlice(s, 0, w) as $.Slice<T>
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export function CompactFunc<T>(
|
|
388
|
+
s: $.Slice<T>,
|
|
389
|
+
eq: EqualCallback<T>,
|
|
390
|
+
): $.Slice<T> {
|
|
391
|
+
if (eq == null) {
|
|
392
|
+
throw new Error('slices.CompactFunc: nil equality function')
|
|
393
|
+
}
|
|
394
|
+
if (s === null || s === undefined || $.len(s) < 2) {
|
|
395
|
+
return s
|
|
396
|
+
}
|
|
397
|
+
let w = 1
|
|
398
|
+
for (let i = 1; i < $.len(s); i++) {
|
|
399
|
+
if (!syncBoolean(eq((s as any)[i - 1] as T, (s as any)[i] as T))) {
|
|
400
|
+
;(s as any)[w] = (s as any)[i]
|
|
401
|
+
w++
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
for (let i = w; i < $.len(s); i++) {
|
|
405
|
+
;(s as any)[i] = clearValue(s)
|
|
406
|
+
}
|
|
407
|
+
return $.goSlice(s, 0, w) as $.Slice<T>
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export function Clip<T>(s: $.Slice<T>): $.Slice<T> {
|
|
411
|
+
if (s == null) {
|
|
412
|
+
return null
|
|
413
|
+
}
|
|
414
|
+
const out = $.makeSlice<T>($.len(s), $.len(s))
|
|
415
|
+
for (let i = 0; i < $.len(s); i++) {
|
|
416
|
+
;(out as any)[i] = (s as any)[i]
|
|
417
|
+
}
|
|
418
|
+
return out
|
|
419
|
+
}
|
|
420
|
+
|
|
207
421
|
export function Equal<T>(s1: $.Slice<T>, s2: $.Slice<T>): boolean {
|
|
208
422
|
const len1 = $.len(s1)
|
|
209
423
|
if (len1 !== $.len(s2)) {
|
|
@@ -220,14 +434,17 @@ export function Equal<T>(s1: $.Slice<T>, s2: $.Slice<T>): boolean {
|
|
|
220
434
|
export function EqualFunc<T, U>(
|
|
221
435
|
s1: $.Slice<T>,
|
|
222
436
|
s2: $.Slice<U>,
|
|
223
|
-
eq:
|
|
437
|
+
eq: EqualCallback<T, U>,
|
|
224
438
|
): boolean {
|
|
439
|
+
if (eq == null) {
|
|
440
|
+
throw new Error('slices.EqualFunc: nil equality function')
|
|
441
|
+
}
|
|
225
442
|
const len1 = $.len(s1)
|
|
226
443
|
if (len1 !== $.len(s2)) {
|
|
227
444
|
return false
|
|
228
445
|
}
|
|
229
446
|
for (let i = 0; i < len1; i++) {
|
|
230
|
-
if (!eq((s1 as any)[i] as T, (s2 as any)[i] as U)) {
|
|
447
|
+
if (!syncBoolean(eq((s1 as any)[i] as T, (s2 as any)[i] as U))) {
|
|
231
448
|
return false
|
|
232
449
|
}
|
|
233
450
|
}
|
|
@@ -243,9 +460,12 @@ export function Index<T>(s: $.Slice<T>, v: T): number {
|
|
|
243
460
|
return -1
|
|
244
461
|
}
|
|
245
462
|
|
|
246
|
-
export function IndexFunc<T>(s: $.Slice<T>, f:
|
|
463
|
+
export function IndexFunc<T>(s: $.Slice<T>, f: PredicateCallback<T>): number {
|
|
464
|
+
if (f == null) {
|
|
465
|
+
throw new Error('slices.IndexFunc: nil predicate function')
|
|
466
|
+
}
|
|
247
467
|
for (let i = 0; i < $.len(s); i++) {
|
|
248
|
-
if (f((s as any)[i] as T)) {
|
|
468
|
+
if (syncBoolean(f((s as any)[i] as T))) {
|
|
249
469
|
return i
|
|
250
470
|
}
|
|
251
471
|
}
|
|
@@ -256,14 +476,16 @@ export function Contains<T>(s: $.Slice<T>, v: T): boolean {
|
|
|
256
476
|
return Index(s, v) >= 0
|
|
257
477
|
}
|
|
258
478
|
|
|
259
|
-
export function ContainsFunc<T>(s: $.Slice<T>, f:
|
|
479
|
+
export function ContainsFunc<T>(s: $.Slice<T>, f: PredicateCallback<T>): boolean {
|
|
260
480
|
return IndexFunc(s, f) >= 0
|
|
261
481
|
}
|
|
262
482
|
|
|
263
483
|
export function Insert<T>(s: $.Slice<T>, i: number, ...v: T[]): $.Slice<T> {
|
|
264
484
|
const length = $.len(s)
|
|
265
485
|
if (i < 0 || i > length) {
|
|
266
|
-
throw new Error(
|
|
486
|
+
throw new Error(
|
|
487
|
+
`slice bounds out of range [${i}:${i}] with length ${length}`,
|
|
488
|
+
)
|
|
267
489
|
}
|
|
268
490
|
if (v.length === 0) {
|
|
269
491
|
return s
|
|
@@ -333,20 +555,29 @@ export function Grow<T>(s: $.Slice<T>, n: number): $.Slice<T> {
|
|
|
333
555
|
* @param s The slice to sort in place
|
|
334
556
|
* @param cmp Comparison function
|
|
335
557
|
*/
|
|
336
|
-
export function SortFunc<T>(
|
|
558
|
+
export function SortFunc<T>(
|
|
559
|
+
s: $.Slice<T>,
|
|
560
|
+
cmp: CompareCallback<T>,
|
|
561
|
+
): void {
|
|
562
|
+
if (cmp == null) {
|
|
563
|
+
throw new Error('slices.SortFunc: nil comparison function')
|
|
564
|
+
}
|
|
337
565
|
if (s === null || s === undefined) {
|
|
338
566
|
return
|
|
339
567
|
}
|
|
340
568
|
const arr = s as any as T[]
|
|
341
|
-
arr.sort(cmp)
|
|
569
|
+
arr.sort((a, b) => syncNumber(cmp(a, b)))
|
|
342
570
|
}
|
|
343
571
|
|
|
344
572
|
export function IsSortedFunc<T>(
|
|
345
573
|
x: $.Slice<T>,
|
|
346
|
-
cmp:
|
|
574
|
+
cmp: CompareCallback<T>,
|
|
347
575
|
): boolean {
|
|
576
|
+
if (cmp == null) {
|
|
577
|
+
throw new Error('slices.IsSortedFunc: nil comparison function')
|
|
578
|
+
}
|
|
348
579
|
for (let i = $.len(x) - 1; i > 0; i--) {
|
|
349
|
-
if (cmp((x as any)[i] as T, (x as any)[i - 1] as T) < 0) {
|
|
580
|
+
if (syncNumber(cmp((x as any)[i] as T, (x as any)[i - 1] as T)) < 0) {
|
|
350
581
|
return false
|
|
351
582
|
}
|
|
352
583
|
}
|
|
@@ -355,23 +586,15 @@ export function IsSortedFunc<T>(
|
|
|
355
586
|
|
|
356
587
|
export function SortStableFunc<T>(
|
|
357
588
|
s: $.Slice<T>,
|
|
358
|
-
cmp:
|
|
589
|
+
cmp: CompareCallback<T>,
|
|
359
590
|
): void {
|
|
591
|
+
if (cmp == null) {
|
|
592
|
+
throw new Error('slices.SortStableFunc: nil comparison function')
|
|
593
|
+
}
|
|
360
594
|
if (s === null || s === undefined) {
|
|
361
595
|
return
|
|
362
596
|
}
|
|
363
|
-
|
|
364
|
-
.map((value, index) => ({ value, index }))
|
|
365
|
-
.sort((a, b) => {
|
|
366
|
-
const result = cmp(a.value, b.value)
|
|
367
|
-
if (result !== 0) {
|
|
368
|
-
return result
|
|
369
|
-
}
|
|
370
|
-
return a.index - b.index
|
|
371
|
-
})
|
|
372
|
-
for (let i = 0; i < sorted.length; i++) {
|
|
373
|
-
;(s as any)[i] = sorted[i].value
|
|
374
|
-
}
|
|
597
|
+
;(s as any as T[]).sort((a, b) => syncNumber(cmp(a, b)))
|
|
375
598
|
}
|
|
376
599
|
|
|
377
600
|
function clearValue<T>(s: $.Slice<T>): T | null {
|
|
@@ -409,14 +632,17 @@ function clearValue<T>(s: $.Slice<T>): T | null {
|
|
|
409
632
|
export function BinarySearchFunc<E, T>(
|
|
410
633
|
x: $.Slice<E>,
|
|
411
634
|
target: T,
|
|
412
|
-
cmp:
|
|
635
|
+
cmp: CompareCallback<E, T>,
|
|
413
636
|
): [number, boolean] {
|
|
637
|
+
if (cmp == null) {
|
|
638
|
+
throw new Error('slices.BinarySearchFunc: nil comparison function')
|
|
639
|
+
}
|
|
414
640
|
let left = 0
|
|
415
641
|
let right = $.len(x)
|
|
416
642
|
|
|
417
643
|
while (left < right) {
|
|
418
644
|
const mid = Math.floor((left + right) / 2)
|
|
419
|
-
const result = cmp((x as any)[mid] as E, target)
|
|
645
|
+
const result = syncNumber(cmp((x as any)[mid] as E, target))
|
|
420
646
|
|
|
421
647
|
if (result < 0) {
|
|
422
648
|
left = mid + 1
|
|
@@ -429,3 +655,24 @@ export function BinarySearchFunc<E, T>(
|
|
|
429
655
|
|
|
430
656
|
return [left, false]
|
|
431
657
|
}
|
|
658
|
+
|
|
659
|
+
function syncNumber(value: SyncCallbackResult<number>): number {
|
|
660
|
+
if (value instanceof Promise) {
|
|
661
|
+
throw new Error('slices: asynchronous callback result is not supported')
|
|
662
|
+
}
|
|
663
|
+
return value
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function syncBoolean(value: SyncCallbackResult<boolean>): boolean {
|
|
667
|
+
if (value instanceof Promise) {
|
|
668
|
+
throw new Error('slices: asynchronous callback result is not supported')
|
|
669
|
+
}
|
|
670
|
+
return value
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
export function BinarySearch<T extends cmp.Ordered>(
|
|
674
|
+
x: $.Slice<T>,
|
|
675
|
+
target: T,
|
|
676
|
+
): [number, boolean] {
|
|
677
|
+
return BinarySearchFunc(x, target, cmp.Compare)
|
|
678
|
+
}
|
package/gs/sort/slice.gs.ts
CHANGED
|
@@ -8,47 +8,98 @@ interface SliceMetadata<T> {
|
|
|
8
8
|
capacity: number
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
type LessFunc = (
|
|
12
|
+
i: number,
|
|
13
|
+
j: number,
|
|
14
|
+
) => boolean | globalThis.Promise<boolean>
|
|
15
|
+
|
|
16
|
+
function setInSlice<T>(slice: $.Slice<T>, i: number, value: T): void {
|
|
13
17
|
if (!slice) return
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const val_j = $.index(slice, j)
|
|
18
|
-
const val_i = temp
|
|
19
|
-
slice[i] = val_j as T
|
|
20
|
-
slice[j] = val_i as T
|
|
18
|
+
|
|
19
|
+
if (Array.isArray(slice) || slice instanceof Uint8Array) {
|
|
20
|
+
;(slice as any)[i] = value
|
|
21
21
|
} else if (typeof slice === 'object' && '__meta__' in slice) {
|
|
22
22
|
const meta = (slice as any).__meta__ as SliceMetadata<T>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
meta.backing[meta.offset + i] = value
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function sortedIndices(n: number, less: LessFunc): Promise<number[]> {
|
|
28
|
+
const indices = Array.from({ length: n }, (_, i) => i)
|
|
29
|
+
await sortIndexRange(indices, 0, indices.length, less)
|
|
30
|
+
return indices
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function sortIndexRange(
|
|
34
|
+
indices: number[],
|
|
35
|
+
lo: number,
|
|
36
|
+
hi: number,
|
|
37
|
+
less: LessFunc,
|
|
38
|
+
): Promise<void> {
|
|
39
|
+
if (hi - lo <= 16) {
|
|
40
|
+
for (let i = lo + 1; i < hi; i++) {
|
|
41
|
+
const value = indices[i]
|
|
42
|
+
let j = i
|
|
43
|
+
while (j > lo && (await less(value, indices[j - 1]))) {
|
|
44
|
+
indices[j] = indices[j - 1]
|
|
45
|
+
j--
|
|
46
|
+
}
|
|
47
|
+
indices[j] = value
|
|
48
|
+
}
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const mid = lo + Math.floor((hi - lo) / 2)
|
|
53
|
+
await sortIndexRange(indices, lo, mid, less)
|
|
54
|
+
await sortIndexRange(indices, mid, hi, less)
|
|
55
|
+
|
|
56
|
+
const merged: number[] = []
|
|
57
|
+
let left = lo
|
|
58
|
+
let right = mid
|
|
59
|
+
while (left < mid && right < hi) {
|
|
60
|
+
if (await less(indices[right], indices[left])) {
|
|
61
|
+
merged.push(indices[right])
|
|
62
|
+
right++
|
|
63
|
+
} else {
|
|
64
|
+
merged.push(indices[left])
|
|
65
|
+
left++
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
while (left < mid) {
|
|
69
|
+
merged.push(indices[left])
|
|
70
|
+
left++
|
|
71
|
+
}
|
|
72
|
+
while (right < hi) {
|
|
73
|
+
merged.push(indices[right])
|
|
74
|
+
right++
|
|
75
|
+
}
|
|
76
|
+
for (let i = 0; i < merged.length; i++) {
|
|
77
|
+
indices[lo + i] = merged[i]
|
|
26
78
|
}
|
|
27
79
|
}
|
|
28
80
|
|
|
29
81
|
// Slice sorts the slice x given the provided less function
|
|
30
82
|
export async function Slice(
|
|
31
83
|
x: $.Slice<any>,
|
|
32
|
-
less:
|
|
84
|
+
less: LessFunc,
|
|
33
85
|
): globalThis.Promise<void> {
|
|
34
86
|
if (!x) return
|
|
35
|
-
|
|
36
|
-
// Simple insertion sort using the provided less function
|
|
87
|
+
|
|
37
88
|
const n = $.len(x)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
89
|
+
const indices = await sortedIndices(n, less)
|
|
90
|
+
const sorted = indices.map((index) => $.index(x, index))
|
|
91
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
92
|
+
setInSlice(x, i, sorted[i])
|
|
42
93
|
}
|
|
43
94
|
}
|
|
44
95
|
|
|
45
96
|
// SliceIsSorted reports whether the slice x is sorted according to the provided less function
|
|
46
97
|
export async function SliceIsSorted(
|
|
47
98
|
x: $.Slice<any>,
|
|
48
|
-
less:
|
|
99
|
+
less: LessFunc,
|
|
49
100
|
): globalThis.Promise<boolean> {
|
|
50
101
|
if (!x) return true
|
|
51
|
-
|
|
102
|
+
|
|
52
103
|
const n = $.len(x)
|
|
53
104
|
for (let i = n - 1; i > 0; i--) {
|
|
54
105
|
if (await less(i, i - 1)) {
|
|
@@ -61,8 +112,7 @@ export async function SliceIsSorted(
|
|
|
61
112
|
// SliceStable sorts the slice x while keeping the original order of equal elements
|
|
62
113
|
export async function SliceStable(
|
|
63
114
|
x: $.Slice<any>,
|
|
64
|
-
less:
|
|
115
|
+
less: LessFunc,
|
|
65
116
|
): globalThis.Promise<void> {
|
|
66
|
-
// For simplicity, use the same sort - can be improved later
|
|
67
117
|
await Slice(x, less)
|
|
68
118
|
}
|