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.
Files changed (121) hide show
  1. package/LICENSE +201 -201
  2. package/NOTICE +94 -94
  3. package/README.md +101 -114
  4. package/bin/asc.js +0 -0
  5. package/bin/asinit.js +6 -6
  6. package/dist/asc.generated.d.ts +10027 -0
  7. package/dist/asc.js +24474 -0
  8. package/dist/asc.js.map +7 -0
  9. package/dist/importmap.json +9 -0
  10. package/dist/toilscript.generated.d.ts +11242 -0
  11. package/dist/toilscript.js +337 -0
  12. package/dist/toilscript.js.map +7 -0
  13. package/dist/web.js +22 -0
  14. package/lib/binaryen.d.ts +2 -2
  15. package/lib/binaryen.js +2 -2
  16. package/package.json +115 -114
  17. package/std/README.md +6 -6
  18. package/std/assembly/array.ts +550 -550
  19. package/std/assembly/arraybuffer.ts +77 -77
  20. package/std/assembly/atomics.ts +127 -127
  21. package/std/assembly/bindings/asyncify.ts +16 -16
  22. package/std/assembly/bindings/dom.ts +291 -291
  23. package/std/assembly/bindings/node.ts +6 -6
  24. package/std/assembly/bitflags.ts +53 -53
  25. package/std/assembly/builtins.ts +2650 -2650
  26. package/std/assembly/byteslice.ts +177 -177
  27. package/std/assembly/compat.ts +2 -2
  28. package/std/assembly/console.ts +42 -42
  29. package/std/assembly/crypto.ts +9 -9
  30. package/std/assembly/dataview.ts +181 -181
  31. package/std/assembly/date.ts +375 -375
  32. package/std/assembly/diagnostics.ts +11 -11
  33. package/std/assembly/encoding.ts +151 -151
  34. package/std/assembly/endian.ts +45 -45
  35. package/std/assembly/error.ts +44 -44
  36. package/std/assembly/fixedarray.ts +173 -173
  37. package/std/assembly/fixedmap.ts +326 -326
  38. package/std/assembly/fixedset.ts +275 -275
  39. package/std/assembly/function.ts +42 -42
  40. package/std/assembly/index.d.ts +2892 -2891
  41. package/std/assembly/iterator.ts +35 -35
  42. package/std/assembly/map.ts +269 -269
  43. package/std/assembly/math.ts +3289 -3289
  44. package/std/assembly/memory.ts +123 -123
  45. package/std/assembly/number.ts +388 -388
  46. package/std/assembly/object.ts +36 -36
  47. package/std/assembly/performance.ts +9 -9
  48. package/std/assembly/pointer.ts +80 -80
  49. package/std/assembly/polyfills.ts +27 -27
  50. package/std/assembly/process.ts +50 -50
  51. package/std/assembly/reference.ts +48 -48
  52. package/std/assembly/regexp.ts +12 -12
  53. package/std/assembly/rt/README.md +83 -83
  54. package/std/assembly/rt/common.ts +81 -81
  55. package/std/assembly/rt/index-incremental.ts +2 -2
  56. package/std/assembly/rt/index-memory.ts +1 -1
  57. package/std/assembly/rt/index-minimal.ts +2 -2
  58. package/std/assembly/rt/index-stub.ts +1 -1
  59. package/std/assembly/rt/index.d.ts +37 -37
  60. package/std/assembly/rt/itcms.ts +419 -419
  61. package/std/assembly/rt/memory-runtime.ts +94 -94
  62. package/std/assembly/rt/rtrace.ts +15 -15
  63. package/std/assembly/rt/stub.ts +133 -133
  64. package/std/assembly/rt/tcms.ts +254 -254
  65. package/std/assembly/rt/tlsf.ts +592 -592
  66. package/std/assembly/rt.ts +90 -90
  67. package/std/assembly/set.ts +225 -225
  68. package/std/assembly/shared/feature.ts +68 -68
  69. package/std/assembly/shared/runtime.ts +13 -13
  70. package/std/assembly/shared/target.ts +11 -11
  71. package/std/assembly/shared/tsconfig.json +11 -11
  72. package/std/assembly/shared/typeinfo.ts +72 -72
  73. package/std/assembly/staticarray.ts +423 -423
  74. package/std/assembly/string.ts +850 -850
  75. package/std/assembly/symbol.ts +114 -114
  76. package/std/assembly/table.ts +16 -16
  77. package/std/assembly/toilscript.ts +16 -0
  78. package/std/assembly/tsconfig.json +6 -6
  79. package/std/assembly/typedarray.ts +1954 -1954
  80. package/std/assembly/uri.ts +17 -17
  81. package/std/assembly/util/bytes.ts +107 -107
  82. package/std/assembly/util/casemap.ts +497 -497
  83. package/std/assembly/util/error.ts +58 -58
  84. package/std/assembly/util/hash.ts +117 -117
  85. package/std/assembly/util/math.ts +1922 -1922
  86. package/std/assembly/util/memory.ts +290 -290
  87. package/std/assembly/util/number.ts +873 -873
  88. package/std/assembly/util/sort.ts +313 -313
  89. package/std/assembly/util/string.ts +1202 -1202
  90. package/std/assembly/util/uri.ts +275 -275
  91. package/std/assembly/vector.ts +4 -4
  92. package/std/assembly.json +16 -16
  93. package/std/portable/index.d.ts +461 -461
  94. package/std/portable/index.js +416 -416
  95. package/std/portable.json +11 -11
  96. package/std/types/assembly/index.d.ts +1 -1
  97. package/std/types/assembly/package.json +2 -2
  98. package/std/types/portable/index.d.ts +1 -1
  99. package/std/types/portable/package.json +2 -2
  100. package/tsconfig-base.json +13 -13
  101. package/util/README.md +23 -23
  102. package/util/browser/fs.js +1 -1
  103. package/util/browser/module.js +5 -5
  104. package/util/browser/path.js +520 -520
  105. package/util/browser/process.js +59 -59
  106. package/util/browser/url.js +23 -23
  107. package/util/cpu.d.ts +9 -9
  108. package/util/cpu.js +42 -42
  109. package/util/find.d.ts +6 -6
  110. package/util/find.js +20 -20
  111. package/util/node.d.ts +21 -21
  112. package/util/node.js +34 -34
  113. package/util/options.d.ts +70 -70
  114. package/util/options.js +262 -262
  115. package/util/terminal.d.ts +52 -52
  116. package/util/terminal.js +35 -35
  117. package/util/text.d.ts +26 -26
  118. package/util/text.js +114 -114
  119. package/util/tsconfig.json +9 -9
  120. package/util/web.d.ts +11 -11
  121. package/util/web.js +33 -33
@@ -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;
@@ -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
+ }