nomen-lang 0.2.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOMEN_AGENTS.md +7 -1
- package/core/System/Arena.nm +166 -0
- package/core/System/Array.nm +30 -161
- package/core/System/BigInt.nm +36 -57
- package/core/System/Buffer.nm +197 -279
- package/core/System/ClassBuffer.nm +120 -130
- package/core/System/Console.nm +4 -2
- package/core/System/Controls/Button.nm +4 -4
- package/core/System/Controls/CheckBox.nm +1 -1
- package/core/System/Controls/LayoutParams.nm +1 -1
- package/core/System/Controls/Text.nm +2 -2
- package/core/System/Controls/TextBox.nm +6 -6
- package/core/System/Controls/Window.nm +2 -2
- package/core/System/Graph.nm +4 -4
- package/core/System/LinkedList.nm +4 -4
- package/core/System/List.nm +6 -6
- package/core/System/Map.nm +33 -30
- package/core/System/Set.nm +24 -24
- package/core/System/Stream/Directory.nm +4 -4
- package/core/System/Stream/File.nm +19 -12
- package/core/System/String.nm +300 -34
- package/core/System/StringBuilder.nm +53 -117
- package/core/System/Text/CharIndex.nm +144 -0
- package/core/System/Text/Chars.nm +32 -0
- package/core/System/Text/JsonTree.nm +48 -96
- package/core/System/Text/Regex.nm +726 -40
- package/core/System/Text/Utf8.nm +163 -0
- package/core/System/bool.nm +2 -1
- package/core/System/char.nm +27 -1
- package/core/System/float.nm +2 -1
- package/core/System/float32.nm +2 -1
- package/core/System/float64.nm +2 -1
- package/core/System/int.nm +4 -2
- package/core/System/int16.nm +2 -1
- package/core/System/int32.nm +2 -1
- package/core/System/int64.nm +2 -1
- package/core/System/int8.nm +2 -1
- package/core/System/ufloat.nm +2 -1
- package/core/System/ufloat32.nm +2 -1
- package/core/System/ufloat64.nm +2 -1
- package/core/System/uint.nm +2 -1
- package/core/System/uint16.nm +2 -1
- package/core/System/uint32.nm +2 -1
- package/core/System/uint64.nm +2 -1
- package/core/System/uint8.nm +2 -1
- package/core/docs/System/BigInt.md +0 -1
- package/dist/index.mjs +5273 -1339
- package/package.json +1 -1
- package/src/index.ts +58 -7
package/core/System/Buffer.nm
CHANGED
|
@@ -1,94 +1,54 @@
|
|
|
1
1
|
// Buffer<T>: a flat buffer of value slots of type T. The value counterpart to
|
|
2
2
|
// ClassBuffer<T>: no per-element freeing, store_int unconstrained. When T is a
|
|
3
3
|
// class, the monomorphizer rewrites a Buffer<T> field to ClassBuffer<T>.
|
|
4
|
+
//
|
|
5
|
+
// Public API is the size-aware family (`alloc`/`grow`/`load`/`replace`/
|
|
6
|
+
// `move`/`modify`/`shift`/`slice` plus the readonly `cap`). `replace` is the
|
|
7
|
+
// public write — it reclaims the displaced element, so it is correct on both
|
|
8
|
+
// fresh and occupied slots. `store` (which assumes a fresh slot and leaks on
|
|
9
|
+
// overwrite), `zero`, the fixed-width `*_u32`/`*_int`/`*_float` primitives,
|
|
10
|
+
// and the raw `data` pointer are `internal` and reserved for the System
|
|
11
|
+
// containers.
|
|
12
|
+
|
|
4
13
|
/**
|
|
5
14
|
* A flat, low-level buffer of value slots of type T — the backing store for arrays and collections
|
|
6
15
|
**/
|
|
7
16
|
pub struct Buffer<T> {
|
|
8
|
-
var uint64 data = 0
|
|
9
|
-
|
|
17
|
+
internal var uint64 data = 0
|
|
18
|
+
// Publicly readable capacity (`i < self.cap` guards every accessor), but
|
|
19
|
+
// only Buffer's own methods may grow it — `readonly`.
|
|
20
|
+
readonly cap = 0
|
|
10
21
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
#arch: aarch64
|
|
20
|
-
str x1, [x19, #16]
|
|
21
|
-
mov x0, x1
|
|
22
|
-
mov x1, #4
|
|
23
|
-
bl _calloc
|
|
24
|
-
str x0, [x19, #8]
|
|
25
|
-
ldr x0, [x19, #16]
|
|
26
|
-
```
|
|
22
|
+
// Allocation / sizing primitives are `unsafe` Nomen single-sourced for
|
|
23
|
+
// both backends. They run once per container op (never per element), so
|
|
24
|
+
// the aarch64 inline-method ABI cost that keeps the per-limb load/store
|
|
25
|
+
// primitives raw (see BigInt.nm) doesn't apply here.
|
|
26
|
+
internal func alloc_u32 = (ref self, int size, out int: out >= size) {
|
|
27
|
+
self.cap = size
|
|
28
|
+
self.data = calloc(size, 4)
|
|
29
|
+
return self.cap
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
func
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
int new_cap = self
|
|
34
|
-
if
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
self
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
#arch: aarch64
|
|
43
|
-
ldr x2, [x19, #16]
|
|
44
|
-
cmp x2, x1
|
|
45
|
-
b.ge .Lbuffer_grow_end
|
|
46
|
-
mov x3, #8
|
|
47
|
-
cmp x2, #0
|
|
48
|
-
csel x3, x3, x2, eq
|
|
49
|
-
cmp x3, x1
|
|
50
|
-
b.ge .Lbuffer_grow_got
|
|
51
|
-
.Lbuffer_grow_loop:
|
|
52
|
-
lsl x3, x3, #1
|
|
53
|
-
cmp x3, x1
|
|
54
|
-
b.lt .Lbuffer_grow_loop
|
|
55
|
-
.Lbuffer_grow_got:
|
|
56
|
-
sub sp, sp, #16
|
|
57
|
-
str x2, [sp, #0]
|
|
58
|
-
str x3, [sp, #8]
|
|
59
|
-
ldr x0, [x19, #8]
|
|
60
|
-
lsl x1, x3, #2
|
|
61
|
-
bl _realloc
|
|
62
|
-
str x0, [x19, #8]
|
|
63
|
-
ldr x2, [sp, #0]
|
|
64
|
-
ldr x3, [sp, #8]
|
|
65
|
-
add sp, sp, #16
|
|
66
|
-
str x3, [x19, #16]
|
|
67
|
-
add x0, x0, x2, lsl #2
|
|
68
|
-
mov x1, #0
|
|
69
|
-
sub x2, x3, x2
|
|
70
|
-
lsl x2, x2, #2
|
|
71
|
-
bl _memset
|
|
72
|
-
.Lbuffer_grow_end:
|
|
73
|
-
ldr x0, [x19, #16]
|
|
74
|
-
```
|
|
32
|
+
internal func grow_u32 = (ref self, int needed, out int: out >= needed) {
|
|
33
|
+
if self.cap >= needed {
|
|
34
|
+
return self.cap
|
|
35
|
+
}
|
|
36
|
+
var int new_cap = self.cap
|
|
37
|
+
if new_cap == 0 {
|
|
38
|
+
new_cap = 8
|
|
39
|
+
}
|
|
40
|
+
while new_cap < needed; new_cap *= 2 {}
|
|
41
|
+
self.data = realloc(self.data, new_cap * 4)
|
|
42
|
+
memset(self.data + self.cap * 4, 0, (new_cap - self.cap) * 4)
|
|
43
|
+
self.cap = new_cap
|
|
44
|
+
return self.cap
|
|
75
45
|
}
|
|
76
46
|
|
|
77
|
-
func
|
|
78
|
-
|
|
79
|
-
#arch: c
|
|
80
|
-
memset((unsigned int*)(unsigned long long)self->data, 0, len * sizeof(unsigned int));
|
|
81
|
-
```
|
|
82
|
-
```
|
|
83
|
-
#arch: aarch64
|
|
84
|
-
ldr x0, [x19, #8]
|
|
85
|
-
lsl x2, x1, #2
|
|
86
|
-
mov x1, #0
|
|
87
|
-
bl _memset
|
|
88
|
-
```
|
|
47
|
+
internal func zero_u32 = (ref self, int len) {
|
|
48
|
+
memset(self.data, 0, len * 4)
|
|
89
49
|
}
|
|
90
50
|
|
|
91
|
-
inline func
|
|
51
|
+
internal inline func load_u32 = (self, int i: i >= 0 && i < self.cap, out uint32) {
|
|
92
52
|
```
|
|
93
53
|
#arch: c
|
|
94
54
|
return ((unsigned int*)(unsigned long long)self->data)[i];
|
|
@@ -103,7 +63,7 @@ pub struct Buffer<T> {
|
|
|
103
63
|
```
|
|
104
64
|
}
|
|
105
65
|
|
|
106
|
-
inline func
|
|
66
|
+
internal inline func store_u32 = (ref self, int i: i >= 0 && i < self.cap, uint32 val) {
|
|
107
67
|
```
|
|
108
68
|
#arch: c
|
|
109
69
|
((unsigned int*)(unsigned long long)self->data)[i] = val;
|
|
@@ -117,7 +77,7 @@ pub struct Buffer<T> {
|
|
|
117
77
|
```
|
|
118
78
|
}
|
|
119
79
|
|
|
120
|
-
inline func
|
|
80
|
+
internal inline func store_or_u32 = (ref self, int i: i >= 0 && i < self.cap, uint32 val) {
|
|
121
81
|
```
|
|
122
82
|
#arch: c
|
|
123
83
|
((unsigned int*)(unsigned long long)self->data)[i] |= val;
|
|
@@ -133,73 +93,28 @@ pub struct Buffer<T> {
|
|
|
133
93
|
```
|
|
134
94
|
}
|
|
135
95
|
|
|
136
|
-
func alloc_int = (ref self, int size, out int: out >= size) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
self
|
|
140
|
-
self->data = (unsigned long long)(long*)calloc(size, sizeof(long));
|
|
141
|
-
return self->cap;
|
|
142
|
-
```
|
|
143
|
-
```
|
|
144
|
-
#arch: aarch64
|
|
145
|
-
str x1, [x19, #16]
|
|
146
|
-
mov x0, x1
|
|
147
|
-
mov x1, #8
|
|
148
|
-
bl _calloc
|
|
149
|
-
str x0, [x19, #8]
|
|
150
|
-
ldr x0, [x19, #16]
|
|
151
|
-
```
|
|
96
|
+
internal func alloc_int = (ref self, int size, out int: out >= size) {
|
|
97
|
+
self.cap = size
|
|
98
|
+
self.data = calloc(size, 8)
|
|
99
|
+
return self.cap
|
|
152
100
|
}
|
|
153
101
|
|
|
154
|
-
func grow_int = (ref self, int needed, out int: out >= needed) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
int new_cap = self
|
|
159
|
-
if
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
self
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
#arch: aarch64
|
|
168
|
-
ldr x2, [x19, #16]
|
|
169
|
-
cmp x2, x1
|
|
170
|
-
b.ge .Lbuffer_grow_int_end
|
|
171
|
-
mov x3, #4
|
|
172
|
-
cmp x2, #0
|
|
173
|
-
csel x3, x3, x2, eq
|
|
174
|
-
cmp x3, x1
|
|
175
|
-
b.ge .Lbuffer_grow_int_got
|
|
176
|
-
.Lbuffer_grow_int_loop:
|
|
177
|
-
lsl x3, x3, #1
|
|
178
|
-
cmp x3, x1
|
|
179
|
-
b.lt .Lbuffer_grow_int_loop
|
|
180
|
-
.Lbuffer_grow_int_got:
|
|
181
|
-
sub sp, sp, #16
|
|
182
|
-
str x2, [sp, #0]
|
|
183
|
-
str x3, [sp, #8]
|
|
184
|
-
ldr x0, [x19, #8]
|
|
185
|
-
lsl x1, x3, #3
|
|
186
|
-
bl _realloc
|
|
187
|
-
str x0, [x19, #8]
|
|
188
|
-
ldr x2, [sp, #0]
|
|
189
|
-
ldr x3, [sp, #8]
|
|
190
|
-
add sp, sp, #16
|
|
191
|
-
str x3, [x19, #16]
|
|
192
|
-
add x0, x0, x2, lsl #3
|
|
193
|
-
mov x1, #0
|
|
194
|
-
sub x2, x3, x2
|
|
195
|
-
lsl x2, x2, #3
|
|
196
|
-
bl _memset
|
|
197
|
-
.Lbuffer_grow_int_end:
|
|
198
|
-
ldr x0, [x19, #16]
|
|
199
|
-
```
|
|
102
|
+
internal func grow_int = (ref self, int needed, out int: out >= needed) {
|
|
103
|
+
if self.cap >= needed {
|
|
104
|
+
return self.cap
|
|
105
|
+
}
|
|
106
|
+
var int new_cap = self.cap
|
|
107
|
+
if new_cap == 0 {
|
|
108
|
+
new_cap = 4
|
|
109
|
+
}
|
|
110
|
+
while new_cap < needed; new_cap *= 2 {}
|
|
111
|
+
self.data = realloc(self.data, new_cap * 8)
|
|
112
|
+
memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
|
|
113
|
+
self.cap = new_cap
|
|
114
|
+
return self.cap
|
|
200
115
|
}
|
|
201
116
|
|
|
202
|
-
inline func load_int = (self, int i: i >= 0 && i < self.cap, out int) {
|
|
117
|
+
internal inline func load_int = (self, int i: i >= 0 && i < self.cap, out int) {
|
|
203
118
|
```
|
|
204
119
|
#arch: c
|
|
205
120
|
return ((long*)(unsigned long long)self->data)[i];
|
|
@@ -213,7 +128,7 @@ pub struct Buffer<T> {
|
|
|
213
128
|
```
|
|
214
129
|
}
|
|
215
130
|
|
|
216
|
-
inline func store_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
|
|
131
|
+
internal inline func store_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
|
|
217
132
|
```
|
|
218
133
|
#arch: c
|
|
219
134
|
((long*)(unsigned long long)self->data)[i] = val;
|
|
@@ -231,7 +146,7 @@ pub struct Buffer<T> {
|
|
|
231
146
|
// the ownership-extracting primitive (used by e.g. List.pop) — unlike
|
|
232
147
|
// load_int (a borrow read), it relinquishes the slot so the buffer no
|
|
233
148
|
// longer owns the value.
|
|
234
|
-
inline func move_int = (ref self, int i: i >= 0 && i < self.cap, out int) {
|
|
149
|
+
internal inline func move_int = (ref self, int i: i >= 0 && i < self.cap, out int) {
|
|
235
150
|
```
|
|
236
151
|
#arch: c
|
|
237
152
|
long *slots = (long*)(unsigned long long)self->data;
|
|
@@ -252,7 +167,7 @@ pub struct Buffer<T> {
|
|
|
252
167
|
// Store into a slot, freeing the previous value when the buffer holds
|
|
253
168
|
// owned class pointers (has_class_refs). For non-class buffers this is a
|
|
254
169
|
// plain store, so it is safe to use anywhere store_int would be.
|
|
255
|
-
inline func replace_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
|
|
170
|
+
internal inline func replace_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
|
|
256
171
|
```
|
|
257
172
|
#arch: c
|
|
258
173
|
((long*)(unsigned long long)self->data)[i] = val;
|
|
@@ -266,18 +181,8 @@ pub struct Buffer<T> {
|
|
|
266
181
|
```
|
|
267
182
|
}
|
|
268
183
|
|
|
269
|
-
inline func zero_int = (ref self, int len) {
|
|
270
|
-
|
|
271
|
-
#arch: c
|
|
272
|
-
memset((long*)(unsigned long long)self->data, 0, len * sizeof(long));
|
|
273
|
-
```
|
|
274
|
-
```
|
|
275
|
-
#arch: aarch64
|
|
276
|
-
ldr x0, [x19, #8]
|
|
277
|
-
lsl x2, x1, #3
|
|
278
|
-
mov x1, #0
|
|
279
|
-
bl _memset
|
|
280
|
-
```
|
|
184
|
+
internal inline func zero_int = (ref self, int len) {
|
|
185
|
+
memset(self.data, 0, len * 8)
|
|
281
186
|
}
|
|
282
187
|
|
|
283
188
|
// T_SIZE-aware primitives for value-struct elements. Slab is sized in
|
|
@@ -285,82 +190,32 @@ pub struct Buffer<T> {
|
|
|
285
190
|
// correctly. Classes route to ClassBuffer<T> (per-element destroy), so T
|
|
286
191
|
// reaching here is always a value type (primitive or struct).
|
|
287
192
|
|
|
288
|
-
func
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
self
|
|
292
|
-
self->data = (unsigned long long)(T*)calloc(size, T_SIZE);
|
|
293
|
-
return self->cap;
|
|
294
|
-
```
|
|
295
|
-
```
|
|
296
|
-
#arch: aarch64
|
|
297
|
-
str x1, [x19, #16]
|
|
298
|
-
mov x0, x1
|
|
299
|
-
mov x1, #T_SIZE
|
|
300
|
-
bl _calloc
|
|
301
|
-
str x0, [x19, #8]
|
|
302
|
-
ldr x0, [x19, #16]
|
|
303
|
-
```
|
|
193
|
+
func alloc = (ref self, int size, out int: out >= size) {
|
|
194
|
+
self.cap = size
|
|
195
|
+
self.data = calloc(size, T_SIZE)
|
|
196
|
+
return self.cap
|
|
304
197
|
}
|
|
305
198
|
|
|
306
|
-
func
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
int new_cap = self
|
|
311
|
-
if
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
self
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
#arch: aarch64
|
|
320
|
-
ldr x2, [x19, #16]
|
|
321
|
-
cmp x2, x1
|
|
322
|
-
b.ge .Lbuffer_grow_T_end
|
|
323
|
-
mov x3, #4
|
|
324
|
-
cmp x2, #0
|
|
325
|
-
csel x3, x3, x2, eq
|
|
326
|
-
cmp x3, x1
|
|
327
|
-
b.ge .Lbuffer_grow_T_got
|
|
328
|
-
.Lbuffer_grow_T_loop:
|
|
329
|
-
lsl x3, x3, #1
|
|
330
|
-
cmp x3, x1
|
|
331
|
-
b.lt .Lbuffer_grow_T_loop
|
|
332
|
-
.Lbuffer_grow_T_got:
|
|
333
|
-
sub sp, sp, #32
|
|
334
|
-
str x2, [sp, #0]
|
|
335
|
-
str x3, [sp, #8]
|
|
336
|
-
mov x4, #T_SIZE
|
|
337
|
-
str x4, [sp, #16]
|
|
338
|
-
ldr x0, [x19, #8]
|
|
339
|
-
madd x1, x3, x4, xzr
|
|
340
|
-
bl _realloc
|
|
341
|
-
str x0, [x19, #8]
|
|
342
|
-
ldr x2, [sp, #0]
|
|
343
|
-
ldr x3, [sp, #8]
|
|
344
|
-
ldr x4, [sp, #16]
|
|
345
|
-
add sp, sp, #32
|
|
346
|
-
str x3, [x19, #16]
|
|
347
|
-
ldr x0, [x19, #8]
|
|
348
|
-
mul x5, x2, x4
|
|
349
|
-
add x0, x0, x5
|
|
350
|
-
sub x2, x3, x2
|
|
351
|
-
mul x2, x2, x4
|
|
352
|
-
mov x1, #0
|
|
353
|
-
bl _memset
|
|
354
|
-
.Lbuffer_grow_T_end:
|
|
355
|
-
ldr x0, [x19, #16]
|
|
356
|
-
```
|
|
199
|
+
func grow = (ref self, int needed, out int: out >= needed) {
|
|
200
|
+
if self.cap >= needed {
|
|
201
|
+
return self.cap
|
|
202
|
+
}
|
|
203
|
+
var int new_cap = self.cap
|
|
204
|
+
if new_cap == 0 {
|
|
205
|
+
new_cap = 4
|
|
206
|
+
}
|
|
207
|
+
while new_cap < needed; new_cap *= 2 {}
|
|
208
|
+
self.data = realloc(self.data, new_cap * T_SIZE)
|
|
209
|
+
memset(self.data + self.cap * T_SIZE, 0, (new_cap - self.cap) * T_SIZE)
|
|
210
|
+
self.cap = new_cap
|
|
211
|
+
return self.cap
|
|
357
212
|
}
|
|
358
213
|
|
|
359
214
|
// `inline` splices the (width-folded at monomorphization) raw body at
|
|
360
215
|
// call sites — the load/store pair behind every container `.at`/`set` is
|
|
361
216
|
// the hottest path in data-heavy code, and the naked-inline path keeps it
|
|
362
217
|
// to a handful of instructions with no call overhead.
|
|
363
|
-
inline func
|
|
218
|
+
inline func load = (self, int i: i >= 0 && i < self.cap, out T) {
|
|
364
219
|
```
|
|
365
220
|
#arch: c
|
|
366
221
|
return ((T*)(unsigned long long)self->data)[i];
|
|
@@ -403,7 +258,15 @@ pub struct Buffer<T> {
|
|
|
403
258
|
```
|
|
404
259
|
}
|
|
405
260
|
|
|
406
|
-
|
|
261
|
+
// Store `val` into slot `i`, which MUST be fresh (calloc'd, or zeroed by
|
|
262
|
+
// move). For an owning T (string, or a struct with string fields) the
|
|
263
|
+
// specialised body deep-copies the incoming value but does NOT free the
|
|
264
|
+
// slot's previous occupant — a second `store` at an occupied index
|
|
265
|
+
// leaks it. To overwrite a live slot use replace (frees the displaced
|
|
266
|
+
// value) — this is the primitive every container's `set` uses.
|
|
267
|
+
// Internal: assumes a FRESH slot (see the contract comment). The public
|
|
268
|
+
// write is `replace`, which is correct on fresh and occupied slots alike.
|
|
269
|
+
internal inline func store = (ref self, int i: i >= 0 && i < self.cap, T val) {
|
|
407
270
|
```
|
|
408
271
|
#arch: c
|
|
409
272
|
((T*)(unsigned long long)self->data)[i] = val;
|
|
@@ -449,7 +312,7 @@ pub struct Buffer<T> {
|
|
|
449
312
|
// the result is treated as OWNED by the borrow checker — the slot is
|
|
450
313
|
// relinquished, so the caller is the sole remaining owner. The value
|
|
451
314
|
// counterpart of ClassBuffer.move_int — used by List.pop for any value T.
|
|
452
|
-
inline func
|
|
315
|
+
inline func move = (ref self, int i: i >= 0 && i < self.cap, move out T) {
|
|
453
316
|
```
|
|
454
317
|
#arch: c
|
|
455
318
|
T* _slots = (T*)(unsigned long long)self->data;
|
|
@@ -505,14 +368,101 @@ pub struct Buffer<T> {
|
|
|
505
368
|
```
|
|
506
369
|
}
|
|
507
370
|
|
|
371
|
+
// Apply `f` to slot `i` in place: the safe way to do a load→modify→store
|
|
372
|
+
// round-trip on a live slot. `f` receives the current value as a borrow
|
|
373
|
+
// (by value) and returns the replacement; the primitive itself handles
|
|
374
|
+
// ownership — the displaced value is freed, and a returned field that
|
|
375
|
+
// aliases the slot's own copy (the round-trip case) is kept, not freed or
|
|
376
|
+
// re-copied. Unlike store this never leaks on overwrite, and unlike
|
|
377
|
+
// replace it is safe to derive the new value from the old one. The
|
|
378
|
+
// returned struct's owning fields must be fresh, null, or identical to
|
|
379
|
+
// the corresponding input fields (no cross-field aliasing). For owning
|
|
380
|
+
// elements (string / structs with string fields) the build phase replaces
|
|
381
|
+
// this body with a specialized one (see owning_buffer_specialize.ts);
|
|
382
|
+
// this raw form is correct for trivially-copyable elements only. NOT
|
|
383
|
+
// `inline`: the body calls through the fn pointer, so splicing the raw
|
|
384
|
+
// block into a caller would bypass the per-element specializations.
|
|
385
|
+
func modify = (ref self, int i: i >= 0 && i < self.cap, func (T, out T) f) {
|
|
386
|
+
```
|
|
387
|
+
#arch: c
|
|
388
|
+
((T*)(unsigned long long)self->data)[i] = f(((T*)(unsigned long long)self->data)[i]);
|
|
389
|
+
```
|
|
390
|
+
```
|
|
391
|
+
#arch: aarch64
|
|
392
|
+
// x19 = self, x1 = i, x2 = f. Scalar elements round-trip through x0
|
|
393
|
+
// (width-matched); larger trivially-copyable structs pass the slot
|
|
394
|
+
// address and an sret pointer (x8) — the fn writes the replacement
|
|
395
|
+
// straight into the slot from a stack-stage copy of the old value.
|
|
396
|
+
stp x20, x21, [sp, #-16]!
|
|
397
|
+
stp x22, x23, [sp, #-16]!
|
|
398
|
+
mov x22, x2
|
|
399
|
+
ldr x9, [x19, #8]
|
|
400
|
+
mov x3, #T_SIZE
|
|
401
|
+
madd x20, x1, x3, xzr
|
|
402
|
+
add x20, x20, x9
|
|
403
|
+
cmp x3, #8
|
|
404
|
+
b.gt .Lbuffer_modify_T_big
|
|
405
|
+
cmp x3, #1
|
|
406
|
+
b.eq .Lbuffer_modify_T_ld1
|
|
407
|
+
cmp x3, #2
|
|
408
|
+
b.eq .Lbuffer_modify_T_ld2
|
|
409
|
+
cmp x3, #4
|
|
410
|
+
b.eq .Lbuffer_modify_T_ld4
|
|
411
|
+
ldr x0, [x20]
|
|
412
|
+
b .Lbuffer_modify_T_call
|
|
413
|
+
.Lbuffer_modify_T_ld1:
|
|
414
|
+
ldrb w0, [x20]
|
|
415
|
+
b .Lbuffer_modify_T_call
|
|
416
|
+
.Lbuffer_modify_T_ld2:
|
|
417
|
+
ldrh w0, [x20]
|
|
418
|
+
b .Lbuffer_modify_T_call
|
|
419
|
+
.Lbuffer_modify_T_ld4:
|
|
420
|
+
ldr w0, [x20]
|
|
421
|
+
.Lbuffer_modify_T_call:
|
|
422
|
+
blr x22
|
|
423
|
+
cmp x3, #1
|
|
424
|
+
b.eq .Lbuffer_modify_T_st1
|
|
425
|
+
cmp x3, #2
|
|
426
|
+
b.eq .Lbuffer_modify_T_st2
|
|
427
|
+
cmp x3, #4
|
|
428
|
+
b.eq .Lbuffer_modify_T_st4
|
|
429
|
+
str x0, [x20]
|
|
430
|
+
b .Lbuffer_modify_T_end
|
|
431
|
+
.Lbuffer_modify_T_st1:
|
|
432
|
+
strb w0, [x20]
|
|
433
|
+
b .Lbuffer_modify_T_end
|
|
434
|
+
.Lbuffer_modify_T_st2:
|
|
435
|
+
strh w0, [x20]
|
|
436
|
+
b .Lbuffer_modify_T_end
|
|
437
|
+
.Lbuffer_modify_T_st4:
|
|
438
|
+
str w0, [x20]
|
|
439
|
+
b .Lbuffer_modify_T_end
|
|
440
|
+
.Lbuffer_modify_T_big:
|
|
441
|
+
add x23, x3, #15
|
|
442
|
+
bic x23, x23, #15
|
|
443
|
+
sub sp, sp, x23
|
|
444
|
+
mov x0, sp
|
|
445
|
+
mov x1, x20
|
|
446
|
+
mov x2, x3
|
|
447
|
+
bl _memcpy
|
|
448
|
+
mov x0, sp
|
|
449
|
+
mov x8, x20
|
|
450
|
+
blr x22
|
|
451
|
+
add sp, sp, x23
|
|
452
|
+
.Lbuffer_modify_T_end:
|
|
453
|
+
ldp x22, x23, [sp], #16
|
|
454
|
+
ldp x20, x21, [sp], #16
|
|
455
|
+
```
|
|
456
|
+
}
|
|
457
|
+
|
|
508
458
|
// Store into a T_SIZE-sized slot, overwriting the previous value. For
|
|
509
459
|
// trivially-destructible value structs this is a plain overwrite. For
|
|
510
460
|
// owning value structs (with string fields), the build phase replaces this
|
|
511
461
|
// body with a specialised version that calls T_destroy on the old slot
|
|
512
462
|
// value, then deep-copies (strdup per string field). See
|
|
513
|
-
// owning_buffer_specialize.ts (both backends). ClassBuffer.
|
|
463
|
+
// owning_buffer_specialize.ts (both backends). ClassBuffer.replace
|
|
514
464
|
// destroys+frees class slots soundly.
|
|
515
|
-
inline func
|
|
465
|
+
inline func replace = (ref self, int i: i >= 0 && i < self.cap, T val) {
|
|
516
466
|
```
|
|
517
467
|
#arch: c
|
|
518
468
|
((T*)(unsigned long long)self->data)[i] = val;
|
|
@@ -556,14 +506,14 @@ pub struct Buffer<T> {
|
|
|
556
506
|
// Move slot src into slot dst: overwrite dst with src's bytes and zero
|
|
557
507
|
// src, so exactly ONE slot owns the value afterwards. The
|
|
558
508
|
// ownership-transferring primitive behind backward-shift deletion
|
|
559
|
-
// (Map/Set.remove) — unlike
|
|
509
|
+
// (Map/Set.remove) — unlike store, which gives the slot its own deep
|
|
560
510
|
// copy and leaves the source slot intact, a shift transfers the source's
|
|
561
511
|
// heap pointers wholesale. For owning elements (string / value structs
|
|
562
512
|
// with string fields) the build replaces this body with a specialized
|
|
563
513
|
// version that also reclaims dst's previous value first (see
|
|
564
514
|
// owning_buffer_specialize.ts); this raw form is correct for
|
|
565
515
|
// trivially-destructible elements only.
|
|
566
|
-
inline func
|
|
516
|
+
inline func shift = (ref self, int dst: dst >= 0 && dst < self.cap, int src: src >= 0 && src < self.cap) {
|
|
567
517
|
```
|
|
568
518
|
#arch: c
|
|
569
519
|
T* _slots = (T*)(unsigned long long)self->data;
|
|
@@ -630,7 +580,7 @@ pub struct Buffer<T> {
|
|
|
630
580
|
// self's scope and is invalidated if self is reassigned. This is the single
|
|
631
581
|
// primitive every other slice (Array<T>, List<T>, user containers) builds
|
|
632
582
|
// on — higher layers just `return self.items.slice(start, end)`.
|
|
633
|
-
func slice = (self, int start: start >= 0, int end: end >= start, out view T) {
|
|
583
|
+
func slice = (self, int start: start >= 0, int end: end >= start && end <= self.cap, out view T) {
|
|
634
584
|
```
|
|
635
585
|
#arch: c
|
|
636
586
|
nomen_view _r;
|
|
@@ -649,22 +599,12 @@ pub struct Buffer<T> {
|
|
|
649
599
|
```
|
|
650
600
|
}
|
|
651
601
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
memset((T*)(unsigned long long)self->data, 0, len * T_SIZE);
|
|
656
|
-
```
|
|
657
|
-
```
|
|
658
|
-
#arch: aarch64
|
|
659
|
-
ldr x0, [x19, #8]
|
|
660
|
-
mov x2, #T_SIZE
|
|
661
|
-
mul x2, x1, x2
|
|
662
|
-
mov x1, #0
|
|
663
|
-
bl _memset
|
|
664
|
-
```
|
|
602
|
+
// Internal: zeroes slots without reclaiming owning elements.
|
|
603
|
+
internal inline func zero = (ref self, int len) {
|
|
604
|
+
memset(self.data, 0, len * T_SIZE)
|
|
665
605
|
}
|
|
666
606
|
|
|
667
|
-
inline func store_or_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
|
|
607
|
+
internal inline func store_or_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
|
|
668
608
|
```
|
|
669
609
|
#arch: c
|
|
670
610
|
((long*)(unsigned long long)self->data)[i] |= val;
|
|
@@ -680,25 +620,13 @@ pub struct Buffer<T> {
|
|
|
680
620
|
```
|
|
681
621
|
}
|
|
682
622
|
|
|
683
|
-
func alloc_float = (ref self, int size, out int: out >= size) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
self
|
|
687
|
-
self->data = (unsigned long long)(double*)calloc(size, sizeof(double));
|
|
688
|
-
return self->cap;
|
|
689
|
-
```
|
|
690
|
-
```
|
|
691
|
-
#arch: aarch64
|
|
692
|
-
str x1, [x19, #16]
|
|
693
|
-
mov x0, x1
|
|
694
|
-
mov x1, #8
|
|
695
|
-
bl _calloc
|
|
696
|
-
str x0, [x19, #8]
|
|
697
|
-
ldr x0, [x19, #16]
|
|
698
|
-
```
|
|
623
|
+
internal func alloc_float = (ref self, int size, out int: out >= size) {
|
|
624
|
+
self.cap = size
|
|
625
|
+
self.data = calloc(size, 8)
|
|
626
|
+
return self.cap
|
|
699
627
|
}
|
|
700
628
|
|
|
701
|
-
inline func load_float = (self, int i: i >= 0 && i < self.cap, out float) {
|
|
629
|
+
internal inline func load_float = (self, int i: i >= 0 && i < self.cap, out float) {
|
|
702
630
|
```
|
|
703
631
|
#arch: c
|
|
704
632
|
return ((double*)(unsigned long long)self->data)[i];
|
|
@@ -712,7 +640,7 @@ pub struct Buffer<T> {
|
|
|
712
640
|
```
|
|
713
641
|
}
|
|
714
642
|
|
|
715
|
-
inline func store_float = (ref self, int i: i >= 0 && i < self.cap, float val) {
|
|
643
|
+
internal inline func store_float = (ref self, int i: i >= 0 && i < self.cap, float val) {
|
|
716
644
|
```
|
|
717
645
|
#arch: c
|
|
718
646
|
((double*)(unsigned long long)self->data)[i] = val;
|
|
@@ -727,20 +655,10 @@ pub struct Buffer<T> {
|
|
|
727
655
|
}
|
|
728
656
|
|
|
729
657
|
func #destroy = () {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
self
|
|
734
|
-
self
|
|
735
|
-
```
|
|
736
|
-
```
|
|
737
|
-
#arch: aarch64
|
|
738
|
-
ldr x0, [x19, #8]
|
|
739
|
-
cbz x0, .Lbuffer_destroy_end
|
|
740
|
-
bl _free
|
|
741
|
-
.Lbuffer_destroy_end:
|
|
742
|
-
str xzr, [x19, #8]
|
|
743
|
-
str xzr, [x19, #16]
|
|
744
|
-
```
|
|
658
|
+
if self.data != 0 {
|
|
659
|
+
free(self.data)
|
|
660
|
+
}
|
|
661
|
+
self.data = 0
|
|
662
|
+
self.cap = 0
|
|
745
663
|
}
|
|
746
664
|
}
|