nomen-lang 0.0.7 → 0.0.8
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/NOMEN_AGENTS.md +235 -0
- package/core/System/Ansi.nm +150 -0
- package/core/System/Array.nm +358 -0
- package/core/System/BigInt.nm +887 -0
- package/core/System/Buffer.nm +526 -0
- package/core/System/Channel.nm +198 -0
- package/core/System/ClassBuffer.nm +229 -0
- package/core/System/Console.nm +211 -0
- package/core/System/Controls/Button.nm +138 -0
- package/core/System/Controls/CheckBox.nm +158 -0
- package/core/System/Controls/Container.nm +1562 -0
- package/core/System/Controls/Control.nm +28 -0
- package/core/System/Controls/Geometry.nm +101 -0
- package/core/System/Controls/Layout.nm +228 -0
- package/core/System/Controls/LayoutParams.nm +50 -0
- package/core/System/Controls/Text.nm +129 -0
- package/core/System/Controls/TextBox.nm +157 -0
- package/core/System/Controls/Window.nm +280 -0
- package/core/System/Disposable.nm +8 -0
- package/core/System/Enumerable.nm +10 -0
- package/core/System/Equatable.nm +10 -0
- package/core/System/Graph.nm +68 -0
- package/core/System/Hashable.nm +13 -0
- package/core/System/Init.nm +21 -0
- package/core/System/LinkedList.nm +64 -0
- package/core/System/List.nm +44 -0
- package/core/System/Map.nm +153 -0
- package/core/System/Math.nm +54 -0
- package/core/System/Mutex.nm +78 -0
- package/core/System/Nursery.nm +27 -0
- package/core/System/Sendable.nm +9 -0
- package/core/System/Set.nm +97 -0
- package/core/System/Stream/Directory.nm +176 -0
- package/core/System/Stream/File.nm +432 -0
- package/core/System/Stream/Http.nm +453 -0
- package/core/System/String.nm +154 -0
- package/core/System/StringBuilder.nm +249 -0
- package/core/System/Stringable.nm +8 -0
- package/core/System/Task.nm +263 -0
- package/core/System/Test.nm +241 -0
- package/core/System/Text/Json.nm +377 -0
- package/core/System/Text/JsonTree.nm +187 -0
- package/core/System/Text/Regex.nm +655 -0
- package/core/System/Time.nm +112 -0
- package/core/System/Tree.nm +70 -0
- package/core/System/Viewable.nm +27 -0
- package/core/System/bool.nm +66 -0
- package/core/System/char.nm +42 -0
- package/core/System/float.nm +43 -0
- package/core/System/int.nm +54 -0
- package/core/System/int64.nm +42 -0
- package/core/System/int8.nm +42 -0
- package/core/System/uint.nm +42 -0
- package/core/System/uint64.nm +42 -0
- package/core/System/uint8.nm +42 -0
- package/core/docs/System/Ansi.md +40 -0
- package/core/docs/System/Array.md +16 -0
- package/core/docs/System/BigInt.md +30 -0
- package/core/docs/System/Buffer.md +31 -0
- package/core/docs/System/Channel.md +10 -0
- package/core/docs/System/ClassBuffer.md +15 -0
- package/core/docs/System/Console.md +13 -0
- package/core/docs/System/Controls/Button.md +12 -0
- package/core/docs/System/Controls/CheckBox.md +15 -0
- package/core/docs/System/Controls/Container.md +82 -0
- package/core/docs/System/Controls/Control.md +5 -0
- package/core/docs/System/Controls/Geometry.md +26 -0
- package/core/docs/System/Controls/Layout.md +37 -0
- package/core/docs/System/Controls/LayoutParams.md +13 -0
- package/core/docs/System/Controls/Text.md +12 -0
- package/core/docs/System/Controls/TextBox.md +13 -0
- package/core/docs/System/Controls/Window.md +20 -0
- package/core/docs/System/Disposable.md +5 -0
- package/core/docs/System/Enumerable.md +5 -0
- package/core/docs/System/Graph.md +17 -0
- package/core/docs/System/Init.md +9 -0
- package/core/docs/System/LinkedList.md +16 -0
- package/core/docs/System/List.md +13 -0
- package/core/docs/System/Map.md +14 -0
- package/core/docs/System/Math.md +11 -0
- package/core/docs/System/Mutex.md +10 -0
- package/core/docs/System/Nursery.md +5 -0
- package/core/docs/System/Sendable.md +5 -0
- package/core/docs/System/Set.md +14 -0
- package/core/docs/System/Stream/Directory.md +12 -0
- package/core/docs/System/Stream/File.md +21 -0
- package/core/docs/System/String.md +14 -0
- package/core/docs/System/StringBuilder.md +12 -0
- package/core/docs/System/Stringable.md +5 -0
- package/core/docs/System/Task.md +15 -0
- package/core/docs/System/Text/Json.md +12 -0
- package/core/docs/System/Text/JsonTree.md +21 -0
- package/core/docs/System/Text/Regex.md +12 -0
- package/core/docs/System/Time.md +11 -0
- package/core/docs/System/Tree.md +18 -0
- package/core/docs/System/Viewable.md +5 -0
- package/core/docs/System/bool.md +9 -0
- package/core/docs/System/char.md +9 -0
- package/core/docs/System/float.md +9 -0
- package/core/docs/System/int.md +10 -0
- package/core/docs/System/int64.md +9 -0
- package/core/docs/System/int8.md +9 -0
- package/core/docs/System/uint.md +9 -0
- package/core/docs/System/uint64.md +9 -0
- package/core/docs/System/uint8.md +9 -0
- package/core/package.jsonc +4 -0
- package/dist/index.mjs +417 -5490
- package/package.json +33 -30
- package/src/args.ts +171 -0
- package/src/index.ts +53 -104
- package/src/init.ts +128 -0
- package/src/test.ts +6 -2
- package/test/fixtures/build/calc.test +0 -0
- package/test/fixtures/build/calc.test.c +0 -969
- package/test/fixtures/build/main.h +0 -170
- package/test/fixtures/calc.test.nm +0 -32
- package/tsconfig.json +0 -21
- package/vite.config.ts +0 -7
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// StringBuilder: a growable byte buffer for incrementally building strings.
|
|
2
|
+
//
|
|
3
|
+
// Appending is O(1) amortized (geometric growth), and `to_string` finalizes
|
|
4
|
+
// the buffer in place (no extra copy). Used by Regex.replace_all and the
|
|
5
|
+
// Json parse/stringify paths to avoid the O(n^2) cost of repeated `string +`
|
|
6
|
+
// concatenation, where each `+` mallocs and copies the whole accumulator.
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A growable byte buffer for incrementally building strings (O(1) amortized append)
|
|
10
|
+
**/
|
|
11
|
+
pub struct StringBuilder {
|
|
12
|
+
var uint64 data = 0
|
|
13
|
+
var len = 0
|
|
14
|
+
var cap = 0
|
|
15
|
+
|
|
16
|
+
// Ensure capacity for at least `needed` bytes. Grows geometrically.
|
|
17
|
+
func ensure = (ref self, int needed) {
|
|
18
|
+
```
|
|
19
|
+
#arch: c
|
|
20
|
+
if (self->cap >= needed) return;
|
|
21
|
+
int new_cap = self->cap;
|
|
22
|
+
if (new_cap == 0) new_cap = 16;
|
|
23
|
+
while (new_cap < needed) new_cap *= 2;
|
|
24
|
+
self->data = (unsigned long long)realloc((void*)(unsigned long long)self->data, new_cap);
|
|
25
|
+
self->cap = new_cap;
|
|
26
|
+
```
|
|
27
|
+
```
|
|
28
|
+
#arch: aarch64
|
|
29
|
+
// x19 = self, x1 = needed
|
|
30
|
+
ldr x2, [x19, #24] // cap
|
|
31
|
+
cmp x2, x1
|
|
32
|
+
b.ge .Lsb_ensure_end
|
|
33
|
+
// pick new_cap
|
|
34
|
+
mov x3, #16
|
|
35
|
+
cmp x2, #0
|
|
36
|
+
csel x3, x3, x2, eq
|
|
37
|
+
.Lsb_ensure_loop:
|
|
38
|
+
cmp x3, x1
|
|
39
|
+
b.ge .Lsb_ensure_grow
|
|
40
|
+
lsl x3, x3, #1
|
|
41
|
+
b .Lsb_ensure_loop
|
|
42
|
+
.Lsb_ensure_grow:
|
|
43
|
+
// save needed (x1) and new_cap (x3) across realloc
|
|
44
|
+
sub sp, sp, #32
|
|
45
|
+
str x1, [sp, #0]
|
|
46
|
+
str x3, [sp, #8]
|
|
47
|
+
str x2, [sp, #16] // old cap (unused after, but keeps stack aligned)
|
|
48
|
+
ldr x0, [x19, #8] // data
|
|
49
|
+
mov x1, x3
|
|
50
|
+
bl _realloc
|
|
51
|
+
str x0, [sp, #24] // saved new data ptr
|
|
52
|
+
ldr x1, [sp, #8] // new_cap
|
|
53
|
+
str x1, [x19, #24] // cap = new_cap
|
|
54
|
+
ldr x0, [sp, #24]
|
|
55
|
+
str x0, [x19, #8] // data = realloc result
|
|
56
|
+
add sp, sp, #32
|
|
57
|
+
.Lsb_ensure_end:
|
|
58
|
+
```
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Append a single byte (char).
|
|
62
|
+
func append_char = (ref self, char c) {
|
|
63
|
+
```
|
|
64
|
+
#arch: c
|
|
65
|
+
int idx = self->len;
|
|
66
|
+
if (idx + 1 >= self->cap) {
|
|
67
|
+
int nc = self->cap;
|
|
68
|
+
if (nc == 0) nc = 16;
|
|
69
|
+
while (nc < idx + 2) nc *= 2;
|
|
70
|
+
self->data = (unsigned long long)realloc((void*)(unsigned long long)self->data, nc);
|
|
71
|
+
self->cap = nc;
|
|
72
|
+
}
|
|
73
|
+
((unsigned char*)(unsigned long long)self->data)[idx] = (unsigned char)c;
|
|
74
|
+
self->len = idx + 1;
|
|
75
|
+
```
|
|
76
|
+
```
|
|
77
|
+
#arch: aarch64
|
|
78
|
+
// x19 = self, w1 = c (low byte)
|
|
79
|
+
// Save c across the ensure/grow call.
|
|
80
|
+
sub sp, sp, #16
|
|
81
|
+
str w1, [sp, #0]
|
|
82
|
+
ldr x1, [x19, #16] // len
|
|
83
|
+
add x1, x1, #2 // need len + 2 bytes (char + null terminator room)
|
|
84
|
+
// inline ensure
|
|
85
|
+
ldr x2, [x19, #24] // cap
|
|
86
|
+
cmp x2, x1
|
|
87
|
+
b.ge .Lsb_ac_store
|
|
88
|
+
mov x3, #16
|
|
89
|
+
cmp x2, #0
|
|
90
|
+
csel x3, x3, x2, eq
|
|
91
|
+
.Lsb_ac_loop:
|
|
92
|
+
cmp x3, x1
|
|
93
|
+
b.ge .Lsb_ac_grow
|
|
94
|
+
lsl x3, x3, #1
|
|
95
|
+
b .Lsb_ac_loop
|
|
96
|
+
.Lsb_ac_grow:
|
|
97
|
+
str x3, [x19, #24] // cap = new_cap
|
|
98
|
+
ldr x0, [x19, #8]
|
|
99
|
+
mov x1, x3
|
|
100
|
+
bl _realloc
|
|
101
|
+
str x0, [x19, #8]
|
|
102
|
+
.Lsb_ac_store:
|
|
103
|
+
ldr w1, [sp, #0] // c
|
|
104
|
+
ldr x0, [x19, #8] // data
|
|
105
|
+
ldr x2, [x19, #16] // len
|
|
106
|
+
strb w1, [x0, x2]
|
|
107
|
+
add x2, x2, #1
|
|
108
|
+
str x2, [x19, #16] // len = len + 1
|
|
109
|
+
add sp, sp, #16
|
|
110
|
+
```
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Append a null-terminated string.
|
|
114
|
+
func append_string = (ref self, string s) {
|
|
115
|
+
```
|
|
116
|
+
#arch: c
|
|
117
|
+
int sl = strlen(s);
|
|
118
|
+
int needed = self->len + sl + 1;
|
|
119
|
+
if (needed > self->cap) {
|
|
120
|
+
int nc = self->cap;
|
|
121
|
+
if (nc == 0) nc = 16;
|
|
122
|
+
while (nc < needed) nc *= 2;
|
|
123
|
+
self->data = (unsigned long long)realloc((void*)(unsigned long long)self->data, nc);
|
|
124
|
+
self->cap = nc;
|
|
125
|
+
}
|
|
126
|
+
memcpy((unsigned char*)(unsigned long long)self->data + self->len, s, sl);
|
|
127
|
+
self->len = self->len + sl;
|
|
128
|
+
```
|
|
129
|
+
```
|
|
130
|
+
#arch: aarch64
|
|
131
|
+
// x19 = self, x1 = s
|
|
132
|
+
// Save s across strlen/realloc.
|
|
133
|
+
mov x0, x1
|
|
134
|
+
sub sp, sp, #32
|
|
135
|
+
str x0, [sp, #0]
|
|
136
|
+
bl _strlen
|
|
137
|
+
str x0, [sp, #8] // sl
|
|
138
|
+
ldr x1, [x19, #16] // len
|
|
139
|
+
add x1, x1, x0 // len + sl
|
|
140
|
+
add x1, x1, #1 // +1 for null room
|
|
141
|
+
// inline ensure(x1)
|
|
142
|
+
ldr x2, [x19, #24]
|
|
143
|
+
cmp x2, x1
|
|
144
|
+
b.ge .Lsb_as_copy
|
|
145
|
+
mov x3, #16
|
|
146
|
+
cmp x2, #0
|
|
147
|
+
csel x3, x3, x2, eq
|
|
148
|
+
.Lsb_as_loop:
|
|
149
|
+
cmp x3, x1
|
|
150
|
+
b.ge .Lsb_as_grow
|
|
151
|
+
lsl x3, x3, #1
|
|
152
|
+
b .Lsb_as_loop
|
|
153
|
+
.Lsb_as_grow:
|
|
154
|
+
str x3, [x19, #24]
|
|
155
|
+
ldr x0, [x19, #8]
|
|
156
|
+
mov x1, x3
|
|
157
|
+
bl _realloc
|
|
158
|
+
str x0, [x19, #8]
|
|
159
|
+
.Lsb_as_copy:
|
|
160
|
+
// memcpy(data + len, s, sl)
|
|
161
|
+
ldr x1, [sp, #8] // sl
|
|
162
|
+
ldr x0, [x19, #8] // data
|
|
163
|
+
ldr x2, [x19, #16] // len
|
|
164
|
+
add x0, x0, x2 // dest = data + len
|
|
165
|
+
ldr x1, [sp, #0] // src = s
|
|
166
|
+
ldr x2, [sp, #8] // n = sl
|
|
167
|
+
bl _memcpy
|
|
168
|
+
// len = len + sl
|
|
169
|
+
ldr x0, [x19, #16]
|
|
170
|
+
ldr x1, [sp, #8]
|
|
171
|
+
add x0, x0, x1
|
|
172
|
+
str x0, [x19, #16]
|
|
173
|
+
add sp, sp, #32
|
|
174
|
+
```
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Finalize: null-terminate, return the byte buffer as a string, and
|
|
178
|
+
// release ownership (sets `data` to 0 so the destructor won't free it).
|
|
179
|
+
func to_string = (ref self, out string) {
|
|
180
|
+
```
|
|
181
|
+
#arch: c
|
|
182
|
+
int idx = self->len;
|
|
183
|
+
int needed = idx + 1;
|
|
184
|
+
if (needed > self->cap) {
|
|
185
|
+
int nc = self->cap;
|
|
186
|
+
if (nc == 0) nc = 16;
|
|
187
|
+
while (nc < needed) nc *= 2;
|
|
188
|
+
self->data = (unsigned long long)realloc((void*)(unsigned long long)self->data, nc);
|
|
189
|
+
self->cap = nc;
|
|
190
|
+
}
|
|
191
|
+
((unsigned char*)(unsigned long long)self->data)[idx] = 0;
|
|
192
|
+
unsigned long long result = self->data;
|
|
193
|
+
self->data = 0;
|
|
194
|
+
return (char*)result;
|
|
195
|
+
```
|
|
196
|
+
```
|
|
197
|
+
#arch: aarch64
|
|
198
|
+
// x19 = self
|
|
199
|
+
ldr x1, [x19, #16] // len
|
|
200
|
+
add x1, x1, #1 // need len + 1
|
|
201
|
+
ldr x2, [x19, #24]
|
|
202
|
+
cmp x2, x1
|
|
203
|
+
b.ge .Lsb_ts_store
|
|
204
|
+
mov x3, #16
|
|
205
|
+
cmp x2, #0
|
|
206
|
+
csel x3, x3, x2, eq
|
|
207
|
+
.Lsb_ts_loop:
|
|
208
|
+
cmp x3, x1
|
|
209
|
+
b.ge .Lsb_ts_grow
|
|
210
|
+
lsl x3, x3, #1
|
|
211
|
+
b .Lsb_ts_loop
|
|
212
|
+
.Lsb_ts_grow:
|
|
213
|
+
str x3, [x19, #24]
|
|
214
|
+
ldr x0, [x19, #8]
|
|
215
|
+
mov x1, x3
|
|
216
|
+
bl _realloc
|
|
217
|
+
str x0, [x19, #8]
|
|
218
|
+
.Lsb_ts_store:
|
|
219
|
+
ldr x0, [x19, #8] // x0 = data (this is what we return)
|
|
220
|
+
ldr x1, [x19, #16] // len
|
|
221
|
+
strb wzr, [x0, x1] // data[len] = 0
|
|
222
|
+
// transfer ownership: clear self->data. x0 retains the old ptr.
|
|
223
|
+
str xzr, [x19, #8]
|
|
224
|
+
```
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Drop the buffer without finalizing (free the byte buffer outright).
|
|
228
|
+
func #destroy = () {
|
|
229
|
+
```
|
|
230
|
+
#arch: c
|
|
231
|
+
if (self->data) {
|
|
232
|
+
free((void*)(unsigned long long)self->data);
|
|
233
|
+
self->data = 0;
|
|
234
|
+
self->len = 0;
|
|
235
|
+
self->cap = 0;
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
```
|
|
239
|
+
#arch: aarch64
|
|
240
|
+
ldr x0, [x19, #8]
|
|
241
|
+
cbz x0, .Lsb_destroy_end
|
|
242
|
+
bl _free
|
|
243
|
+
str xzr, [x19, #8]
|
|
244
|
+
str xzr, [x19, #16]
|
|
245
|
+
str xzr, [x19, #24]
|
|
246
|
+
.Lsb_destroy_end:
|
|
247
|
+
```
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
// Task runtime — thread-pool-backed execution primitive.
|
|
2
|
+
//
|
|
3
|
+
// Spawned tasks run on a shared worker pool. The pool starts at a
|
|
4
|
+
// configurable size (default 4, via Task.set_pool_size before the first
|
|
5
|
+
// spawn) and grows on demand up to 64 workers when every worker is busy,
|
|
6
|
+
// preventing deadlocks from nested spawns. The pool drains and joins all
|
|
7
|
+
// workers at process exit; Task.shutdown_pool does this explicitly.
|
|
8
|
+
//
|
|
9
|
+
// The pool infrastructure (types, worker loop, submit, shutdown, cancel
|
|
10
|
+
// thread-local) lives in build_spawn_node and is emitted as file-scope C
|
|
11
|
+
// on the first spawn — not in Task's own methods — so that Task can be
|
|
12
|
+
// generic without duplicating the pool per instantiation.
|
|
13
|
+
//
|
|
14
|
+
// See ASYNC.md for the design.
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A handle to an asynchronously-running computation, backed by a shared thread pool
|
|
18
|
+
**/
|
|
19
|
+
pub class Task<T> : Sendable {
|
|
20
|
+
pub var uint64 handle = 0
|
|
21
|
+
pub var done = false
|
|
22
|
+
pub var uint64 result_slot = 0
|
|
23
|
+
pub var uint64 cancel_flag = 0
|
|
24
|
+
pub var uint64 future = 0
|
|
25
|
+
|
|
26
|
+
// Block until the task finishes. Idempotent — calling twice is safe, and
|
|
27
|
+
// a Task captured from a nursery spawn can be waited on here AND joined
|
|
28
|
+
// by the nursery at block exit (both wait on the same shared future).
|
|
29
|
+
pub func wait = (ref self) {
|
|
30
|
+
```
|
|
31
|
+
#arch: c
|
|
32
|
+
if (self->future) {
|
|
33
|
+
__nomen_future_wait((struct nomen_future *)self->future);
|
|
34
|
+
} else if (self->handle && !self->done) {
|
|
35
|
+
void *ret;
|
|
36
|
+
pthread_join((pthread_t)self->handle, &ret);
|
|
37
|
+
self->handle = 0;
|
|
38
|
+
self->done = 1;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
```
|
|
42
|
+
#arch: aarch64
|
|
43
|
+
// if (self->future) goto wait_future
|
|
44
|
+
ldr x0, [x19, #40]
|
|
45
|
+
cbz x0, .Lwait_handle
|
|
46
|
+
bl ___nomen_future_wait
|
|
47
|
+
b .Lwait_done
|
|
48
|
+
.Lwait_handle:
|
|
49
|
+
// else if (self->handle && !self->done)
|
|
50
|
+
ldr x0, [x19, #8]
|
|
51
|
+
cbz x0, .Lwait_done
|
|
52
|
+
ldrb w1, [x19, #16]
|
|
53
|
+
cbnz w1, .Lwait_done
|
|
54
|
+
// pthread_join((pthread_t)self->handle, &ret)
|
|
55
|
+
sub sp, sp, #16
|
|
56
|
+
mov x1, sp
|
|
57
|
+
bl _pthread_join
|
|
58
|
+
add sp, sp, #16
|
|
59
|
+
// self->handle = 0; self->done = 1
|
|
60
|
+
str xzr, [x19, #8]
|
|
61
|
+
mov w0, #1
|
|
62
|
+
strb w0, [x19, #16]
|
|
63
|
+
.Lwait_done:
|
|
64
|
+
```
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Block until the task finishes, then return its result as T.
|
|
68
|
+
// The spawn build phase allocates a heap slot (owned by the future) and
|
|
69
|
+
// the trampoline writes the function's return value there before exiting.
|
|
70
|
+
// For tasks with no return value (void functions), returns the zero value.
|
|
71
|
+
pub func result = (ref self, out T) {
|
|
72
|
+
```
|
|
73
|
+
#arch: c
|
|
74
|
+
if (self->future) {
|
|
75
|
+
__nomen_future_wait((struct nomen_future *)self->future);
|
|
76
|
+
} else if (self->handle && !self->done) {
|
|
77
|
+
void *ret;
|
|
78
|
+
pthread_join((pthread_t)self->handle, &ret);
|
|
79
|
+
self->handle = 0;
|
|
80
|
+
self->done = 1;
|
|
81
|
+
}
|
|
82
|
+
return *(T *)self->result_slot;
|
|
83
|
+
```
|
|
84
|
+
```
|
|
85
|
+
#arch: aarch64
|
|
86
|
+
// Wait for completion (same as wait method)
|
|
87
|
+
ldr x0, [x19, #40]
|
|
88
|
+
cbz x0, .Lresult_handle
|
|
89
|
+
bl ___nomen_future_wait
|
|
90
|
+
b .Lresult_read
|
|
91
|
+
.Lresult_handle:
|
|
92
|
+
ldr x0, [x19, #8]
|
|
93
|
+
cbz x0, .Lresult_read
|
|
94
|
+
ldrb w1, [x19, #16]
|
|
95
|
+
cbnz w1, .Lresult_read
|
|
96
|
+
sub sp, sp, #16
|
|
97
|
+
mov x1, sp
|
|
98
|
+
bl _pthread_join
|
|
99
|
+
add sp, sp, #16
|
|
100
|
+
str xzr, [x19, #8]
|
|
101
|
+
mov w0, #1
|
|
102
|
+
strb w0, [x19, #16]
|
|
103
|
+
.Lresult_read:
|
|
104
|
+
// return *(T *)self->result_slot
|
|
105
|
+
ldr x0, [x19, #24]
|
|
106
|
+
ldr x0, [x0]
|
|
107
|
+
```
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Block until the task finishes, then return its result as a uint64.
|
|
111
|
+
// Convenience for the common case; same as result() for uint64 tasks.
|
|
112
|
+
pub func result_uint64 = (ref self, out uint64) {
|
|
113
|
+
```
|
|
114
|
+
#arch: c
|
|
115
|
+
if (self->future) {
|
|
116
|
+
__nomen_future_wait((struct nomen_future *)self->future);
|
|
117
|
+
} else if (self->handle && !self->done) {
|
|
118
|
+
void *ret;
|
|
119
|
+
pthread_join((pthread_t)self->handle, &ret);
|
|
120
|
+
self->handle = 0;
|
|
121
|
+
self->done = 1;
|
|
122
|
+
}
|
|
123
|
+
return *(unsigned long long *)self->result_slot;
|
|
124
|
+
```
|
|
125
|
+
```
|
|
126
|
+
#arch: aarch64
|
|
127
|
+
// Wait for completion
|
|
128
|
+
ldr x0, [x19, #40]
|
|
129
|
+
cbz x0, .Lru64_handle
|
|
130
|
+
bl ___nomen_future_wait
|
|
131
|
+
b .Lru64_read
|
|
132
|
+
.Lru64_handle:
|
|
133
|
+
ldr x0, [x19, #8]
|
|
134
|
+
cbz x0, .Lru64_read
|
|
135
|
+
ldrb w1, [x19, #16]
|
|
136
|
+
cbnz w1, .Lru64_read
|
|
137
|
+
sub sp, sp, #16
|
|
138
|
+
mov x1, sp
|
|
139
|
+
bl _pthread_join
|
|
140
|
+
add sp, sp, #16
|
|
141
|
+
str xzr, [x19, #8]
|
|
142
|
+
mov w0, #1
|
|
143
|
+
strb w0, [x19, #16]
|
|
144
|
+
.Lru64_read:
|
|
145
|
+
// return *(unsigned long long *)self->result_slot
|
|
146
|
+
ldr x0, [x19, #24]
|
|
147
|
+
ldr x0, [x0]
|
|
148
|
+
```
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Request that the task stop. Cooperative — the task observes this via
|
|
152
|
+
// `Task.current_cancelled()` at its own checkpoints. No preemption.
|
|
153
|
+
pub func cancel = (ref self) {
|
|
154
|
+
```
|
|
155
|
+
#arch: c
|
|
156
|
+
if (self->cancel_flag) {
|
|
157
|
+
*(unsigned long long *)self->cancel_flag = 1;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
```
|
|
161
|
+
#arch: aarch64
|
|
162
|
+
// if (self->cancel_flag) *(self->cancel_flag) = 1
|
|
163
|
+
ldr x0, [x19, #32]
|
|
164
|
+
cbz x0, .Lcancel_done
|
|
165
|
+
mov x1, #1
|
|
166
|
+
str x1, [x0]
|
|
167
|
+
.Lcancel_done:
|
|
168
|
+
```
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Has the currently-running task been asked to cancel? Returns false
|
|
172
|
+
// when called from outside any spawned task (e.g. main thread).
|
|
173
|
+
pub func current_cancelled = (out bool) {
|
|
174
|
+
```
|
|
175
|
+
#arch: c
|
|
176
|
+
return __nomen_current_cancel_flag && *__nomen_current_cancel_flag;
|
|
177
|
+
```
|
|
178
|
+
```
|
|
179
|
+
#arch: aarch64_use_c
|
|
180
|
+
return __nomen_current_cancel_flag && *__nomen_current_cancel_flag;
|
|
181
|
+
```
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Configure the worker pool size. Must be called before the first spawn
|
|
185
|
+
// — once the pool is initialized (lazily on first submit), the initial
|
|
186
|
+
// size is fixed (the pool still grows on demand up to 64 workers when
|
|
187
|
+
// every worker is busy). No-op if called after init (silent; check the
|
|
188
|
+
// return value to detect). Returns 1 if the size was set, 0 otherwise.
|
|
189
|
+
pub func set_pool_size = (int n, out int) {
|
|
190
|
+
```
|
|
191
|
+
#arch: c
|
|
192
|
+
if (__nomen_pool_init || n <= 0) return 0;
|
|
193
|
+
__nomen_pool_size = n;
|
|
194
|
+
return 1;
|
|
195
|
+
```
|
|
196
|
+
```
|
|
197
|
+
#arch: aarch64
|
|
198
|
+
// x0 = n (first arg)
|
|
199
|
+
// if (__nomen_pool_init || n <= 0) return 0
|
|
200
|
+
adrp x1, ___nomen_pool_init@PAGE
|
|
201
|
+
add x1, x1, ___nomen_pool_init@PAGEOFF
|
|
202
|
+
ldr w2, [x1]
|
|
203
|
+
cbnz w2, .Lsps_zero
|
|
204
|
+
cmp x0, #0
|
|
205
|
+
b.le .Lsps_zero
|
|
206
|
+
// __nomen_pool_size = n
|
|
207
|
+
adrp x1, ___nomen_pool_size@PAGE
|
|
208
|
+
add x1, x1, ___nomen_pool_size@PAGEOFF
|
|
209
|
+
str w0, [x1]
|
|
210
|
+
mov x0, #1
|
|
211
|
+
b .Lsps_done
|
|
212
|
+
.Lsps_zero:
|
|
213
|
+
mov x0, #0
|
|
214
|
+
.Lsps_done:
|
|
215
|
+
```
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Shut the worker pool down: drain the queue, join every worker, and
|
|
219
|
+
// free the pool. Runs automatically at process exit (registered via
|
|
220
|
+
// atexit on first submit), so outstanding fire-and-forget tasks always
|
|
221
|
+
// complete before exit. Call explicitly to join all outstanding tasks
|
|
222
|
+
// before continuing; the pool re-initializes on the next spawn.
|
|
223
|
+
// Do NOT call from a spawned task (a worker joining its coworkers
|
|
224
|
+
// deadlocks).
|
|
225
|
+
pub func shutdown_pool = () {
|
|
226
|
+
```
|
|
227
|
+
#arch: c
|
|
228
|
+
__nomen_pool_shutdown();
|
|
229
|
+
```
|
|
230
|
+
```
|
|
231
|
+
#arch: aarch64
|
|
232
|
+
bl ___nomen_pool_shutdown
|
|
233
|
+
```
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Release this handle's reference to the future. The future owns the
|
|
237
|
+
// result slot and cancel flag; it (and they) are freed only when the
|
|
238
|
+
// last reference — this handle, the running trampoline, or a tracking
|
|
239
|
+
// nursery — is released. The Task instance itself is freed by the
|
|
240
|
+
// auto-free pass after #destroy returns.
|
|
241
|
+
pub func #destroy = () {
|
|
242
|
+
```
|
|
243
|
+
#arch: c
|
|
244
|
+
if (self->future) {
|
|
245
|
+
__nomen_future_release((struct nomen_future *)self->future);
|
|
246
|
+
self->future = 0;
|
|
247
|
+
self->result_slot = 0;
|
|
248
|
+
self->cancel_flag = 0;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
```
|
|
252
|
+
#arch: aarch64
|
|
253
|
+
// if (self->future) { release; zero fields }
|
|
254
|
+
ldr x0, [x19, #40]
|
|
255
|
+
cbz x0, .Ldestroy_done
|
|
256
|
+
bl ___nomen_future_release
|
|
257
|
+
str xzr, [x19, #40]
|
|
258
|
+
str xzr, [x19, #24]
|
|
259
|
+
str xzr, [x19, #32]
|
|
260
|
+
.Ldestroy_done:
|
|
261
|
+
```
|
|
262
|
+
}
|
|
263
|
+
}
|