toilscript 0.0.1 → 0.1.1
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/LICENSE +201 -201
- package/NOTICE +94 -94
- package/README.md +101 -114
- package/bin/asc.js +0 -0
- package/bin/asinit.js +6 -6
- package/dist/asc.generated.d.ts +10027 -0
- package/dist/asc.js +24474 -0
- package/dist/asc.js.map +7 -0
- package/dist/importmap.json +9 -0
- package/dist/toilscript.generated.d.ts +11242 -0
- package/dist/toilscript.js +337 -0
- package/dist/toilscript.js.map +7 -0
- package/dist/web.js +22 -0
- package/lib/binaryen.d.ts +2 -2
- package/lib/binaryen.js +2 -2
- package/package.json +115 -114
- package/std/README.md +6 -6
- package/std/assembly/array.ts +550 -550
- package/std/assembly/arraybuffer.ts +77 -77
- package/std/assembly/atomics.ts +127 -127
- package/std/assembly/bindings/asyncify.ts +16 -16
- package/std/assembly/bindings/dom.ts +291 -291
- package/std/assembly/bindings/node.ts +6 -6
- package/std/assembly/bitflags.ts +53 -53
- package/std/assembly/builtins.ts +2650 -2650
- package/std/assembly/byteslice.ts +177 -177
- package/std/assembly/compat.ts +2 -2
- package/std/assembly/console.ts +42 -42
- package/std/assembly/crypto.ts +9 -9
- package/std/assembly/dataview.ts +181 -181
- package/std/assembly/date.ts +375 -375
- package/std/assembly/diagnostics.ts +11 -11
- package/std/assembly/encoding.ts +151 -151
- package/std/assembly/endian.ts +45 -45
- package/std/assembly/error.ts +44 -44
- package/std/assembly/fixedarray.ts +173 -173
- package/std/assembly/fixedmap.ts +326 -326
- package/std/assembly/fixedset.ts +275 -275
- package/std/assembly/function.ts +42 -42
- package/std/assembly/index.d.ts +2892 -2891
- package/std/assembly/iterator.ts +35 -35
- package/std/assembly/map.ts +269 -269
- package/std/assembly/math.ts +3289 -3289
- package/std/assembly/memory.ts +123 -123
- package/std/assembly/number.ts +388 -388
- package/std/assembly/object.ts +36 -36
- package/std/assembly/performance.ts +9 -9
- package/std/assembly/pointer.ts +80 -80
- package/std/assembly/polyfills.ts +27 -27
- package/std/assembly/process.ts +50 -50
- package/std/assembly/reference.ts +48 -48
- package/std/assembly/regexp.ts +12 -12
- package/std/assembly/rt/README.md +83 -83
- package/std/assembly/rt/common.ts +81 -81
- package/std/assembly/rt/index-incremental.ts +2 -2
- package/std/assembly/rt/index-memory.ts +1 -1
- package/std/assembly/rt/index-minimal.ts +2 -2
- package/std/assembly/rt/index-stub.ts +1 -1
- package/std/assembly/rt/index.d.ts +37 -37
- package/std/assembly/rt/itcms.ts +419 -419
- package/std/assembly/rt/memory-runtime.ts +94 -94
- package/std/assembly/rt/rtrace.ts +15 -15
- package/std/assembly/rt/stub.ts +133 -133
- package/std/assembly/rt/tcms.ts +254 -254
- package/std/assembly/rt/tlsf.ts +592 -592
- package/std/assembly/rt.ts +90 -90
- package/std/assembly/set.ts +225 -225
- package/std/assembly/shared/feature.ts +68 -68
- package/std/assembly/shared/runtime.ts +13 -13
- package/std/assembly/shared/target.ts +11 -11
- package/std/assembly/shared/tsconfig.json +11 -11
- package/std/assembly/shared/typeinfo.ts +72 -72
- package/std/assembly/staticarray.ts +423 -423
- package/std/assembly/string.ts +850 -850
- package/std/assembly/symbol.ts +114 -114
- package/std/assembly/table.ts +16 -16
- package/std/assembly/toilscript.ts +16 -0
- package/std/assembly/tsconfig.json +6 -6
- package/std/assembly/typedarray.ts +1954 -1954
- package/std/assembly/uri.ts +17 -17
- package/std/assembly/util/bytes.ts +107 -107
- package/std/assembly/util/casemap.ts +497 -497
- package/std/assembly/util/error.ts +58 -58
- package/std/assembly/util/hash.ts +117 -117
- package/std/assembly/util/math.ts +1922 -1922
- package/std/assembly/util/memory.ts +290 -290
- package/std/assembly/util/number.ts +873 -873
- package/std/assembly/util/sort.ts +313 -313
- package/std/assembly/util/string.ts +1202 -1202
- package/std/assembly/util/uri.ts +275 -275
- package/std/assembly/vector.ts +4 -4
- package/std/assembly.json +16 -16
- package/std/portable/index.d.ts +461 -461
- package/std/portable/index.js +416 -416
- package/std/portable.json +11 -11
- package/std/types/assembly/index.d.ts +1 -1
- package/std/types/assembly/package.json +2 -2
- package/std/types/portable/index.d.ts +1 -1
- package/std/types/portable/package.json +2 -2
- package/tsconfig-base.json +13 -13
- package/util/README.md +23 -23
- package/util/browser/fs.js +1 -1
- package/util/browser/module.js +5 -5
- package/util/browser/path.js +520 -520
- package/util/browser/process.js +59 -59
- package/util/browser/url.js +23 -23
- package/util/cpu.d.ts +9 -9
- package/util/cpu.js +42 -42
- package/util/find.d.ts +6 -6
- package/util/find.js +20 -20
- package/util/node.d.ts +21 -21
- package/util/node.js +34 -34
- package/util/options.d.ts +70 -70
- package/util/options.js +262 -262
- package/util/terminal.d.ts +52 -52
- package/util/terminal.js +35 -35
- package/util/text.d.ts +26 -26
- package/util/text.js +114 -114
- package/util/tsconfig.json +9 -9
- package/util/web.d.ts +11 -11
- package/util/web.js +33 -33
package/std/assembly/rt.ts
CHANGED
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
import { Typeinfo, TypeinfoFlags } from "./shared/typeinfo";
|
|
2
|
-
import { Runtime } from "shared/runtime";
|
|
3
|
-
import { E_INDEXOUTOFRANGE } from "./util/error";
|
|
4
|
-
import { ArrayBufferView } from "./arraybuffer";
|
|
5
|
-
|
|
6
|
-
// @ts-ignore: decorator
|
|
7
|
-
@builtin
|
|
8
|
-
export declare const __rtti_base: usize;
|
|
9
|
-
|
|
10
|
-
// @ts-ignore: decorator
|
|
11
|
-
@builtin @unsafe
|
|
12
|
-
export declare function __visit_globals(cookie: u32): void;
|
|
13
|
-
|
|
14
|
-
// @ts-ignore: decorator
|
|
15
|
-
@builtin @unsafe
|
|
16
|
-
export declare function __visit_members(ref: usize, cookie: u32): void;
|
|
17
|
-
|
|
18
|
-
// @ts-ignore: decorator
|
|
19
|
-
@unsafe
|
|
20
|
-
export function __typeinfo(id: u32): TypeinfoFlags {
|
|
21
|
-
let ptr = __rtti_base;
|
|
22
|
-
if (id > load<u32>(ptr)) throw new Error(E_INDEXOUTOFRANGE);
|
|
23
|
-
return changetype<Typeinfo>(ptr + sizeof<u32>() + id * offsetof<Typeinfo>()).flags;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// @ts-ignore: decorator
|
|
27
|
-
@unsafe
|
|
28
|
-
export function __newBuffer(size: usize, id: u32, data: usize = 0): usize {
|
|
29
|
-
let buffer = __new(size, id);
|
|
30
|
-
if (data) memory.copy(buffer, data, size);
|
|
31
|
-
return buffer;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// @ts-ignore: decorator
|
|
35
|
-
@unsafe
|
|
36
|
-
export function __newArray(length: i32, alignLog2: usize, id: u32, data: usize = 0): usize {
|
|
37
|
-
let bufferSize = <usize>length << alignLog2;
|
|
38
|
-
// make sure `buffer` is tracked by the shadow stack
|
|
39
|
-
let buffer = changetype<ArrayBuffer>(__newBuffer(bufferSize, idof<ArrayBuffer>(), data));
|
|
40
|
-
// ...since allocating the array may trigger GC steps
|
|
41
|
-
let array = __new(offsetof<i32[]>(), id);
|
|
42
|
-
store<usize>(array, changetype<usize>(buffer), offsetof<ArrayBufferView>("buffer"));
|
|
43
|
-
if (ASC_RUNTIME != Runtime.Memory) {
|
|
44
|
-
__link(array, changetype<usize>(buffer), false);
|
|
45
|
-
}
|
|
46
|
-
store<usize>(array, changetype<usize>(buffer), offsetof<ArrayBufferView>("dataStart"));
|
|
47
|
-
store<i32>(array, bufferSize, offsetof<ArrayBufferView>("byteLength"));
|
|
48
|
-
store<i32>(array, length, offsetof<i32[]>("length_"));
|
|
49
|
-
return array;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// @ts-ignore: decorator
|
|
53
|
-
@global @unsafe
|
|
54
|
-
export function __tostack(ptr: usize): usize {
|
|
55
|
-
return ptr;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// These are provided by the respective implementation, included as another entry file by asc:
|
|
59
|
-
|
|
60
|
-
// // @ts-ignore: decorator
|
|
61
|
-
// @builtin @unsafe
|
|
62
|
-
// export declare function __alloc(size: usize): usize;
|
|
63
|
-
|
|
64
|
-
// // @ts-ignore: decorator
|
|
65
|
-
// @builtin @unsafe
|
|
66
|
-
// export declare function __realloc(ptr: usize, size: usize): usize;
|
|
67
|
-
|
|
68
|
-
// // @ts-ignore: decorator
|
|
69
|
-
// @builtin @unsafe
|
|
70
|
-
// export declare function __free(ptr: usize): void;
|
|
71
|
-
|
|
72
|
-
// // @ts-ignore: decorator
|
|
73
|
-
// @builtin @unsafe
|
|
74
|
-
// export declare function __new(size: usize, id: u32): usize;
|
|
75
|
-
|
|
76
|
-
// // @ts-ignore: decorator
|
|
77
|
-
// @builtin @unsafe
|
|
78
|
-
// export declare function __renew(ptr: usize, size: usize): usize;
|
|
79
|
-
|
|
80
|
-
// // @ts-ignore: decorator
|
|
81
|
-
// @builtin @unsafe
|
|
82
|
-
// export declare function __link(parentPtr: usize, childPtr: usize, expectMultiple: bool): void;
|
|
83
|
-
|
|
84
|
-
// // @ts-ignore: decorator
|
|
85
|
-
// @builtin @unsafe
|
|
86
|
-
// export declare function __collect(): void;
|
|
87
|
-
|
|
88
|
-
// // @ts-ignore: decorator
|
|
89
|
-
// @builtin @unsafe
|
|
90
|
-
// export declare function __visit(ptr: usize, cookie: u32): void;
|
|
1
|
+
import { Typeinfo, TypeinfoFlags } from "./shared/typeinfo";
|
|
2
|
+
import { Runtime } from "shared/runtime";
|
|
3
|
+
import { E_INDEXOUTOFRANGE } from "./util/error";
|
|
4
|
+
import { ArrayBufferView } from "./arraybuffer";
|
|
5
|
+
|
|
6
|
+
// @ts-ignore: decorator
|
|
7
|
+
@builtin
|
|
8
|
+
export declare const __rtti_base: usize;
|
|
9
|
+
|
|
10
|
+
// @ts-ignore: decorator
|
|
11
|
+
@builtin @unsafe
|
|
12
|
+
export declare function __visit_globals(cookie: u32): void;
|
|
13
|
+
|
|
14
|
+
// @ts-ignore: decorator
|
|
15
|
+
@builtin @unsafe
|
|
16
|
+
export declare function __visit_members(ref: usize, cookie: u32): void;
|
|
17
|
+
|
|
18
|
+
// @ts-ignore: decorator
|
|
19
|
+
@unsafe
|
|
20
|
+
export function __typeinfo(id: u32): TypeinfoFlags {
|
|
21
|
+
let ptr = __rtti_base;
|
|
22
|
+
if (id > load<u32>(ptr)) throw new Error(E_INDEXOUTOFRANGE);
|
|
23
|
+
return changetype<Typeinfo>(ptr + sizeof<u32>() + id * offsetof<Typeinfo>()).flags;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// @ts-ignore: decorator
|
|
27
|
+
@unsafe
|
|
28
|
+
export function __newBuffer(size: usize, id: u32, data: usize = 0): usize {
|
|
29
|
+
let buffer = __new(size, id);
|
|
30
|
+
if (data) memory.copy(buffer, data, size);
|
|
31
|
+
return buffer;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// @ts-ignore: decorator
|
|
35
|
+
@unsafe
|
|
36
|
+
export function __newArray(length: i32, alignLog2: usize, id: u32, data: usize = 0): usize {
|
|
37
|
+
let bufferSize = <usize>length << alignLog2;
|
|
38
|
+
// make sure `buffer` is tracked by the shadow stack
|
|
39
|
+
let buffer = changetype<ArrayBuffer>(__newBuffer(bufferSize, idof<ArrayBuffer>(), data));
|
|
40
|
+
// ...since allocating the array may trigger GC steps
|
|
41
|
+
let array = __new(offsetof<i32[]>(), id);
|
|
42
|
+
store<usize>(array, changetype<usize>(buffer), offsetof<ArrayBufferView>("buffer"));
|
|
43
|
+
if (ASC_RUNTIME != Runtime.Memory) {
|
|
44
|
+
__link(array, changetype<usize>(buffer), false);
|
|
45
|
+
}
|
|
46
|
+
store<usize>(array, changetype<usize>(buffer), offsetof<ArrayBufferView>("dataStart"));
|
|
47
|
+
store<i32>(array, bufferSize, offsetof<ArrayBufferView>("byteLength"));
|
|
48
|
+
store<i32>(array, length, offsetof<i32[]>("length_"));
|
|
49
|
+
return array;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// @ts-ignore: decorator
|
|
53
|
+
@global @unsafe
|
|
54
|
+
export function __tostack(ptr: usize): usize {
|
|
55
|
+
return ptr;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// These are provided by the respective implementation, included as another entry file by asc:
|
|
59
|
+
|
|
60
|
+
// // @ts-ignore: decorator
|
|
61
|
+
// @builtin @unsafe
|
|
62
|
+
// export declare function __alloc(size: usize): usize;
|
|
63
|
+
|
|
64
|
+
// // @ts-ignore: decorator
|
|
65
|
+
// @builtin @unsafe
|
|
66
|
+
// export declare function __realloc(ptr: usize, size: usize): usize;
|
|
67
|
+
|
|
68
|
+
// // @ts-ignore: decorator
|
|
69
|
+
// @builtin @unsafe
|
|
70
|
+
// export declare function __free(ptr: usize): void;
|
|
71
|
+
|
|
72
|
+
// // @ts-ignore: decorator
|
|
73
|
+
// @builtin @unsafe
|
|
74
|
+
// export declare function __new(size: usize, id: u32): usize;
|
|
75
|
+
|
|
76
|
+
// // @ts-ignore: decorator
|
|
77
|
+
// @builtin @unsafe
|
|
78
|
+
// export declare function __renew(ptr: usize, size: usize): usize;
|
|
79
|
+
|
|
80
|
+
// // @ts-ignore: decorator
|
|
81
|
+
// @builtin @unsafe
|
|
82
|
+
// export declare function __link(parentPtr: usize, childPtr: usize, expectMultiple: bool): void;
|
|
83
|
+
|
|
84
|
+
// // @ts-ignore: decorator
|
|
85
|
+
// @builtin @unsafe
|
|
86
|
+
// export declare function __collect(): void;
|
|
87
|
+
|
|
88
|
+
// // @ts-ignore: decorator
|
|
89
|
+
// @builtin @unsafe
|
|
90
|
+
// export declare function __visit(ptr: usize, cookie: u32): void;
|
package/std/assembly/set.ts
CHANGED
|
@@ -1,225 +1,225 @@
|
|
|
1
|
-
/// <reference path="./rt/index.d.ts" />
|
|
2
|
-
|
|
3
|
-
import { HASH } from "./util/hash";
|
|
4
|
-
import { Runtime } from "shared/runtime";
|
|
5
|
-
|
|
6
|
-
// A deterministic hash set based on CloseTable from https://github.com/jorendorff/dht
|
|
7
|
-
|
|
8
|
-
// @ts-ignore: decorator
|
|
9
|
-
@inline const INITIAL_CAPACITY = 4;
|
|
10
|
-
|
|
11
|
-
// @ts-ignore: decorator
|
|
12
|
-
@inline const FILL_FACTOR_N = 8;
|
|
13
|
-
|
|
14
|
-
// @ts-ignore: decorator
|
|
15
|
-
@inline const FILL_FACTOR_D = 3;
|
|
16
|
-
|
|
17
|
-
// @ts-ignore: decorator
|
|
18
|
-
@inline const FREE_FACTOR_N = 3;
|
|
19
|
-
|
|
20
|
-
// @ts-ignore: decorator
|
|
21
|
-
@inline const FREE_FACTOR_D = 4;
|
|
22
|
-
|
|
23
|
-
/** Structure of a set entry. */
|
|
24
|
-
@unmanaged class SetEntry<K> {
|
|
25
|
-
key: K;
|
|
26
|
-
taggedNext: usize; // LSB=1 indicates EMPTY
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Empty bit. */
|
|
30
|
-
// @ts-ignore: decorator
|
|
31
|
-
@inline const EMPTY: usize = 1 << 0;
|
|
32
|
-
|
|
33
|
-
/** Size of a bucket. */
|
|
34
|
-
// @ts-ignore: decorator
|
|
35
|
-
@inline const BUCKET_SIZE = sizeof<usize>();
|
|
36
|
-
|
|
37
|
-
/** Computes the alignment of an entry. */
|
|
38
|
-
// @ts-ignore: decorator
|
|
39
|
-
@inline
|
|
40
|
-
function ENTRY_ALIGN<T>(): usize {
|
|
41
|
-
// can align to 4 instead of 8 if 32-bit and K is <= 32-bits
|
|
42
|
-
const align = (sizeof<T>() > sizeof<usize>() ? sizeof<T>() : sizeof<usize>()) - 1;
|
|
43
|
-
return align;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Computes the aligned size of an entry. */
|
|
47
|
-
// @ts-ignore: decorator
|
|
48
|
-
@inline
|
|
49
|
-
function ENTRY_SIZE<T>(): usize {
|
|
50
|
-
const align = ENTRY_ALIGN<T>();
|
|
51
|
-
const size = (offsetof<SetEntry<T>>() + align) & ~align;
|
|
52
|
-
return size;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export class Set<T> {
|
|
56
|
-
|
|
57
|
-
// buckets referencing their respective first entry, usize[bucketsMask + 1]
|
|
58
|
-
private buckets: ArrayBuffer = new ArrayBuffer(INITIAL_CAPACITY * <i32>BUCKET_SIZE);
|
|
59
|
-
private bucketsMask: u32 = INITIAL_CAPACITY - 1;
|
|
60
|
-
|
|
61
|
-
// entries in insertion order, SetEntry<K>[entriesCapacity]
|
|
62
|
-
private entries: ArrayBuffer = new ArrayBuffer(INITIAL_CAPACITY * <i32>ENTRY_SIZE<T>());
|
|
63
|
-
private entriesCapacity: i32 = INITIAL_CAPACITY;
|
|
64
|
-
private entriesOffset: i32 = 0;
|
|
65
|
-
private entriesCount: i32 = 0;
|
|
66
|
-
|
|
67
|
-
constructor() {
|
|
68
|
-
/* nop */
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
get size(): i32 {
|
|
72
|
-
return this.entriesCount;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
clear(): void {
|
|
76
|
-
this.buckets = new ArrayBuffer(INITIAL_CAPACITY * <i32>BUCKET_SIZE);
|
|
77
|
-
this.bucketsMask = INITIAL_CAPACITY - 1;
|
|
78
|
-
this.entries = new ArrayBuffer(INITIAL_CAPACITY * <i32>ENTRY_SIZE<T>());
|
|
79
|
-
this.entriesCapacity = INITIAL_CAPACITY;
|
|
80
|
-
this.entriesOffset = 0;
|
|
81
|
-
this.entriesCount = 0;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
private find(key: T, hashCode: u32): SetEntry<T> | null {
|
|
85
|
-
let entry = load<SetEntry<T>>( // unmanaged!
|
|
86
|
-
changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE
|
|
87
|
-
);
|
|
88
|
-
while (entry) {
|
|
89
|
-
let taggedNext = entry.taggedNext;
|
|
90
|
-
if (!(taggedNext & EMPTY) && entry.key == key) return entry;
|
|
91
|
-
entry = changetype<SetEntry<T>>(taggedNext & ~EMPTY);
|
|
92
|
-
}
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
@operator("[]")
|
|
97
|
-
has(key: T): bool {
|
|
98
|
-
return this.find(key, HASH<T>(key)) != null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
add(key: T): this {
|
|
102
|
-
let hashCode = HASH<T>(key);
|
|
103
|
-
let entry = this.find(key, hashCode); // unmanaged!
|
|
104
|
-
if (!entry) {
|
|
105
|
-
// check if rehashing is necessary
|
|
106
|
-
if (this.entriesOffset == this.entriesCapacity) {
|
|
107
|
-
this.rehash(
|
|
108
|
-
this.entriesCount < this.entriesCapacity * FREE_FACTOR_N / FREE_FACTOR_D
|
|
109
|
-
? this.bucketsMask // just rehash if 1/4+ entries are empty
|
|
110
|
-
: (this.bucketsMask << 1) | 1 // grow capacity to next 2^N
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
// append new entry
|
|
114
|
-
entry = changetype<SetEntry<T>>(changetype<usize>(this.entries) + <usize>(this.entriesOffset++) * ENTRY_SIZE<T>());
|
|
115
|
-
entry.key = key;
|
|
116
|
-
if (isManaged<T>()) {
|
|
117
|
-
if (ASC_RUNTIME != Runtime.Memory) {
|
|
118
|
-
__link(changetype<usize>(this), changetype<usize>(key), true);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
++this.entriesCount;
|
|
122
|
-
// link with previous entry in bucket
|
|
123
|
-
let bucketPtrBase = changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE;
|
|
124
|
-
entry.taggedNext = load<usize>(bucketPtrBase);
|
|
125
|
-
store<usize>(bucketPtrBase, changetype<usize>(entry));
|
|
126
|
-
}
|
|
127
|
-
return this;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
@operator("[]=")
|
|
131
|
-
private __set(key: T, value: bool): void {
|
|
132
|
-
if (value) this.add(key);
|
|
133
|
-
else this.delete(key);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
delete(key: T): bool {
|
|
137
|
-
let entry = this.find(key, HASH<T>(key)); // unmanaged!
|
|
138
|
-
if (!entry) return false;
|
|
139
|
-
entry.taggedNext |= EMPTY;
|
|
140
|
-
--this.entriesCount;
|
|
141
|
-
// check if rehashing is appropriate
|
|
142
|
-
let halfBucketsMask = this.bucketsMask >> 1;
|
|
143
|
-
if (
|
|
144
|
-
halfBucketsMask + 1 >= max<u32>(INITIAL_CAPACITY, this.entriesCount) &&
|
|
145
|
-
this.entriesCount < this.entriesCapacity * FREE_FACTOR_N / FREE_FACTOR_D
|
|
146
|
-
) this.rehash(halfBucketsMask);
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private rehash(newBucketsMask: u32): void {
|
|
151
|
-
let newBucketsCapacity = <i32>(newBucketsMask + 1);
|
|
152
|
-
let newBuckets = new ArrayBuffer(newBucketsCapacity * <i32>BUCKET_SIZE);
|
|
153
|
-
let newEntriesCapacity = newBucketsCapacity * FILL_FACTOR_N / FILL_FACTOR_D;
|
|
154
|
-
let newEntries = new ArrayBuffer(newEntriesCapacity * <i32>ENTRY_SIZE<T>());
|
|
155
|
-
|
|
156
|
-
// copy old entries to new entries
|
|
157
|
-
let oldPtr = changetype<usize>(this.entries);
|
|
158
|
-
let oldEnd = oldPtr + <usize>this.entriesOffset * ENTRY_SIZE<T>();
|
|
159
|
-
let newPtr = changetype<usize>(newEntries);
|
|
160
|
-
while (oldPtr != oldEnd) {
|
|
161
|
-
let oldEntry = changetype<SetEntry<T>>(oldPtr); // unmanaged!
|
|
162
|
-
if (!(oldEntry.taggedNext & EMPTY)) {
|
|
163
|
-
let newEntry = changetype<SetEntry<T>>(newPtr); // unmanaged!
|
|
164
|
-
let oldEntryKey = oldEntry.key;
|
|
165
|
-
newEntry.key = oldEntryKey;
|
|
166
|
-
let newBucketIndex = HASH<T>(oldEntryKey) & newBucketsMask;
|
|
167
|
-
let newBucketPtrBase = changetype<usize>(newBuckets) + <usize>newBucketIndex * BUCKET_SIZE;
|
|
168
|
-
newEntry.taggedNext = load<usize>(newBucketPtrBase);
|
|
169
|
-
store<usize>(newBucketPtrBase, newPtr);
|
|
170
|
-
newPtr += ENTRY_SIZE<T>();
|
|
171
|
-
}
|
|
172
|
-
oldPtr += ENTRY_SIZE<T>();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
this.buckets = newBuckets;
|
|
176
|
-
this.bucketsMask = newBucketsMask;
|
|
177
|
-
this.entries = newEntries;
|
|
178
|
-
this.entriesCapacity = newEntriesCapacity;
|
|
179
|
-
this.entriesOffset = this.entriesCount;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
values(): T[] {
|
|
183
|
-
// FIXME: this is preliminary, needs iterators/closures
|
|
184
|
-
let start = changetype<usize>(this.entries);
|
|
185
|
-
let size = this.entriesOffset;
|
|
186
|
-
let values = new Array<T>(size);
|
|
187
|
-
let length = 0;
|
|
188
|
-
for (let i = 0; i < size; ++i) {
|
|
189
|
-
let entry = changetype<SetEntry<T>>(start + <usize>i * ENTRY_SIZE<T>());
|
|
190
|
-
if (!(entry.taggedNext & EMPTY)) {
|
|
191
|
-
unchecked(values[length++] = entry.key);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
values.length = length;
|
|
195
|
-
return values;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
toString(): string {
|
|
199
|
-
return "[object Set]";
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// RT integration
|
|
203
|
-
|
|
204
|
-
@unsafe private __visit(cookie: u32): void {
|
|
205
|
-
if (ASC_RUNTIME != Runtime.Memory) {
|
|
206
|
-
__visit(changetype<usize>(this.buckets), cookie);
|
|
207
|
-
let entries = changetype<usize>(this.entries);
|
|
208
|
-
if (isManaged<T>()) {
|
|
209
|
-
let cur = entries;
|
|
210
|
-
let end = cur + <usize>this.entriesOffset * ENTRY_SIZE<T>();
|
|
211
|
-
while (cur < end) {
|
|
212
|
-
let entry = changetype<SetEntry<T>>(cur);
|
|
213
|
-
if (!(entry.taggedNext & EMPTY)) {
|
|
214
|
-
let val = changetype<usize>(entry.key);
|
|
215
|
-
if (isNullable<T>()) {
|
|
216
|
-
if (val) __visit(val, cookie);
|
|
217
|
-
} else __visit(val, cookie);
|
|
218
|
-
}
|
|
219
|
-
cur += ENTRY_SIZE<T>();
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
__visit(entries, cookie);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
1
|
+
/// <reference path="./rt/index.d.ts" />
|
|
2
|
+
|
|
3
|
+
import { HASH } from "./util/hash";
|
|
4
|
+
import { Runtime } from "shared/runtime";
|
|
5
|
+
|
|
6
|
+
// A deterministic hash set based on CloseTable from https://github.com/jorendorff/dht
|
|
7
|
+
|
|
8
|
+
// @ts-ignore: decorator
|
|
9
|
+
@inline const INITIAL_CAPACITY = 4;
|
|
10
|
+
|
|
11
|
+
// @ts-ignore: decorator
|
|
12
|
+
@inline const FILL_FACTOR_N = 8;
|
|
13
|
+
|
|
14
|
+
// @ts-ignore: decorator
|
|
15
|
+
@inline const FILL_FACTOR_D = 3;
|
|
16
|
+
|
|
17
|
+
// @ts-ignore: decorator
|
|
18
|
+
@inline const FREE_FACTOR_N = 3;
|
|
19
|
+
|
|
20
|
+
// @ts-ignore: decorator
|
|
21
|
+
@inline const FREE_FACTOR_D = 4;
|
|
22
|
+
|
|
23
|
+
/** Structure of a set entry. */
|
|
24
|
+
@unmanaged class SetEntry<K> {
|
|
25
|
+
key: K;
|
|
26
|
+
taggedNext: usize; // LSB=1 indicates EMPTY
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Empty bit. */
|
|
30
|
+
// @ts-ignore: decorator
|
|
31
|
+
@inline const EMPTY: usize = 1 << 0;
|
|
32
|
+
|
|
33
|
+
/** Size of a bucket. */
|
|
34
|
+
// @ts-ignore: decorator
|
|
35
|
+
@inline const BUCKET_SIZE = sizeof<usize>();
|
|
36
|
+
|
|
37
|
+
/** Computes the alignment of an entry. */
|
|
38
|
+
// @ts-ignore: decorator
|
|
39
|
+
@inline
|
|
40
|
+
function ENTRY_ALIGN<T>(): usize {
|
|
41
|
+
// can align to 4 instead of 8 if 32-bit and K is <= 32-bits
|
|
42
|
+
const align = (sizeof<T>() > sizeof<usize>() ? sizeof<T>() : sizeof<usize>()) - 1;
|
|
43
|
+
return align;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Computes the aligned size of an entry. */
|
|
47
|
+
// @ts-ignore: decorator
|
|
48
|
+
@inline
|
|
49
|
+
function ENTRY_SIZE<T>(): usize {
|
|
50
|
+
const align = ENTRY_ALIGN<T>();
|
|
51
|
+
const size = (offsetof<SetEntry<T>>() + align) & ~align;
|
|
52
|
+
return size;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class Set<T> {
|
|
56
|
+
|
|
57
|
+
// buckets referencing their respective first entry, usize[bucketsMask + 1]
|
|
58
|
+
private buckets: ArrayBuffer = new ArrayBuffer(INITIAL_CAPACITY * <i32>BUCKET_SIZE);
|
|
59
|
+
private bucketsMask: u32 = INITIAL_CAPACITY - 1;
|
|
60
|
+
|
|
61
|
+
// entries in insertion order, SetEntry<K>[entriesCapacity]
|
|
62
|
+
private entries: ArrayBuffer = new ArrayBuffer(INITIAL_CAPACITY * <i32>ENTRY_SIZE<T>());
|
|
63
|
+
private entriesCapacity: i32 = INITIAL_CAPACITY;
|
|
64
|
+
private entriesOffset: i32 = 0;
|
|
65
|
+
private entriesCount: i32 = 0;
|
|
66
|
+
|
|
67
|
+
constructor() {
|
|
68
|
+
/* nop */
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get size(): i32 {
|
|
72
|
+
return this.entriesCount;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
clear(): void {
|
|
76
|
+
this.buckets = new ArrayBuffer(INITIAL_CAPACITY * <i32>BUCKET_SIZE);
|
|
77
|
+
this.bucketsMask = INITIAL_CAPACITY - 1;
|
|
78
|
+
this.entries = new ArrayBuffer(INITIAL_CAPACITY * <i32>ENTRY_SIZE<T>());
|
|
79
|
+
this.entriesCapacity = INITIAL_CAPACITY;
|
|
80
|
+
this.entriesOffset = 0;
|
|
81
|
+
this.entriesCount = 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private find(key: T, hashCode: u32): SetEntry<T> | null {
|
|
85
|
+
let entry = load<SetEntry<T>>( // unmanaged!
|
|
86
|
+
changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE
|
|
87
|
+
);
|
|
88
|
+
while (entry) {
|
|
89
|
+
let taggedNext = entry.taggedNext;
|
|
90
|
+
if (!(taggedNext & EMPTY) && entry.key == key) return entry;
|
|
91
|
+
entry = changetype<SetEntry<T>>(taggedNext & ~EMPTY);
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@operator("[]")
|
|
97
|
+
has(key: T): bool {
|
|
98
|
+
return this.find(key, HASH<T>(key)) != null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
add(key: T): this {
|
|
102
|
+
let hashCode = HASH<T>(key);
|
|
103
|
+
let entry = this.find(key, hashCode); // unmanaged!
|
|
104
|
+
if (!entry) {
|
|
105
|
+
// check if rehashing is necessary
|
|
106
|
+
if (this.entriesOffset == this.entriesCapacity) {
|
|
107
|
+
this.rehash(
|
|
108
|
+
this.entriesCount < this.entriesCapacity * FREE_FACTOR_N / FREE_FACTOR_D
|
|
109
|
+
? this.bucketsMask // just rehash if 1/4+ entries are empty
|
|
110
|
+
: (this.bucketsMask << 1) | 1 // grow capacity to next 2^N
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
// append new entry
|
|
114
|
+
entry = changetype<SetEntry<T>>(changetype<usize>(this.entries) + <usize>(this.entriesOffset++) * ENTRY_SIZE<T>());
|
|
115
|
+
entry.key = key;
|
|
116
|
+
if (isManaged<T>()) {
|
|
117
|
+
if (ASC_RUNTIME != Runtime.Memory) {
|
|
118
|
+
__link(changetype<usize>(this), changetype<usize>(key), true);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
++this.entriesCount;
|
|
122
|
+
// link with previous entry in bucket
|
|
123
|
+
let bucketPtrBase = changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE;
|
|
124
|
+
entry.taggedNext = load<usize>(bucketPtrBase);
|
|
125
|
+
store<usize>(bucketPtrBase, changetype<usize>(entry));
|
|
126
|
+
}
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@operator("[]=")
|
|
131
|
+
private __set(key: T, value: bool): void {
|
|
132
|
+
if (value) this.add(key);
|
|
133
|
+
else this.delete(key);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
delete(key: T): bool {
|
|
137
|
+
let entry = this.find(key, HASH<T>(key)); // unmanaged!
|
|
138
|
+
if (!entry) return false;
|
|
139
|
+
entry.taggedNext |= EMPTY;
|
|
140
|
+
--this.entriesCount;
|
|
141
|
+
// check if rehashing is appropriate
|
|
142
|
+
let halfBucketsMask = this.bucketsMask >> 1;
|
|
143
|
+
if (
|
|
144
|
+
halfBucketsMask + 1 >= max<u32>(INITIAL_CAPACITY, this.entriesCount) &&
|
|
145
|
+
this.entriesCount < this.entriesCapacity * FREE_FACTOR_N / FREE_FACTOR_D
|
|
146
|
+
) this.rehash(halfBucketsMask);
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private rehash(newBucketsMask: u32): void {
|
|
151
|
+
let newBucketsCapacity = <i32>(newBucketsMask + 1);
|
|
152
|
+
let newBuckets = new ArrayBuffer(newBucketsCapacity * <i32>BUCKET_SIZE);
|
|
153
|
+
let newEntriesCapacity = newBucketsCapacity * FILL_FACTOR_N / FILL_FACTOR_D;
|
|
154
|
+
let newEntries = new ArrayBuffer(newEntriesCapacity * <i32>ENTRY_SIZE<T>());
|
|
155
|
+
|
|
156
|
+
// copy old entries to new entries
|
|
157
|
+
let oldPtr = changetype<usize>(this.entries);
|
|
158
|
+
let oldEnd = oldPtr + <usize>this.entriesOffset * ENTRY_SIZE<T>();
|
|
159
|
+
let newPtr = changetype<usize>(newEntries);
|
|
160
|
+
while (oldPtr != oldEnd) {
|
|
161
|
+
let oldEntry = changetype<SetEntry<T>>(oldPtr); // unmanaged!
|
|
162
|
+
if (!(oldEntry.taggedNext & EMPTY)) {
|
|
163
|
+
let newEntry = changetype<SetEntry<T>>(newPtr); // unmanaged!
|
|
164
|
+
let oldEntryKey = oldEntry.key;
|
|
165
|
+
newEntry.key = oldEntryKey;
|
|
166
|
+
let newBucketIndex = HASH<T>(oldEntryKey) & newBucketsMask;
|
|
167
|
+
let newBucketPtrBase = changetype<usize>(newBuckets) + <usize>newBucketIndex * BUCKET_SIZE;
|
|
168
|
+
newEntry.taggedNext = load<usize>(newBucketPtrBase);
|
|
169
|
+
store<usize>(newBucketPtrBase, newPtr);
|
|
170
|
+
newPtr += ENTRY_SIZE<T>();
|
|
171
|
+
}
|
|
172
|
+
oldPtr += ENTRY_SIZE<T>();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.buckets = newBuckets;
|
|
176
|
+
this.bucketsMask = newBucketsMask;
|
|
177
|
+
this.entries = newEntries;
|
|
178
|
+
this.entriesCapacity = newEntriesCapacity;
|
|
179
|
+
this.entriesOffset = this.entriesCount;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
values(): T[] {
|
|
183
|
+
// FIXME: this is preliminary, needs iterators/closures
|
|
184
|
+
let start = changetype<usize>(this.entries);
|
|
185
|
+
let size = this.entriesOffset;
|
|
186
|
+
let values = new Array<T>(size);
|
|
187
|
+
let length = 0;
|
|
188
|
+
for (let i = 0; i < size; ++i) {
|
|
189
|
+
let entry = changetype<SetEntry<T>>(start + <usize>i * ENTRY_SIZE<T>());
|
|
190
|
+
if (!(entry.taggedNext & EMPTY)) {
|
|
191
|
+
unchecked(values[length++] = entry.key);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
values.length = length;
|
|
195
|
+
return values;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
toString(): string {
|
|
199
|
+
return "[object Set]";
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// RT integration
|
|
203
|
+
|
|
204
|
+
@unsafe private __visit(cookie: u32): void {
|
|
205
|
+
if (ASC_RUNTIME != Runtime.Memory) {
|
|
206
|
+
__visit(changetype<usize>(this.buckets), cookie);
|
|
207
|
+
let entries = changetype<usize>(this.entries);
|
|
208
|
+
if (isManaged<T>()) {
|
|
209
|
+
let cur = entries;
|
|
210
|
+
let end = cur + <usize>this.entriesOffset * ENTRY_SIZE<T>();
|
|
211
|
+
while (cur < end) {
|
|
212
|
+
let entry = changetype<SetEntry<T>>(cur);
|
|
213
|
+
if (!(entry.taggedNext & EMPTY)) {
|
|
214
|
+
let val = changetype<usize>(entry.key);
|
|
215
|
+
if (isNullable<T>()) {
|
|
216
|
+
if (val) __visit(val, cookie);
|
|
217
|
+
} else __visit(val, cookie);
|
|
218
|
+
}
|
|
219
|
+
cur += ENTRY_SIZE<T>();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
__visit(entries, cookie);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|