nomen-lang 0.2.3 → 0.3.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/core/System/Arena.nm +166 -0
- package/core/System/Array.nm +30 -161
- package/core/System/BigInt.nm +31 -42
- package/core/System/Buffer.nm +67 -249
- package/core/System/ClassBuffer.nm +43 -105
- package/core/System/Controls/LayoutParams.nm +1 -1
- package/core/System/Map.nm +3 -0
- package/core/System/String.nm +256 -19
- 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 +33 -81
- package/core/System/Text/Regex.nm +726 -40
- package/core/System/Text/Utf8.nm +163 -0
- package/core/System/char.nm +25 -0
- package/dist/index.mjs +3477 -405
- package/package.json +1 -1
- package/src/index.ts +58 -7
package/core/System/Buffer.nm
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
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
|
+
|
|
4
5
|
/**
|
|
5
6
|
* A flat, low-level buffer of value slots of type T — the backing store for arrays and collections
|
|
6
7
|
**/
|
|
@@ -8,84 +9,33 @@ pub struct Buffer<T> {
|
|
|
8
9
|
var uint64 data = 0
|
|
9
10
|
var cap = 0
|
|
10
11
|
|
|
12
|
+
// Allocation / sizing primitives are `unsafe` Nomen single-sourced for
|
|
13
|
+
// both backends. They run once per container op (never per element), so
|
|
14
|
+
// the aarch64 inline-method ABI cost that keeps the per-limb load/store
|
|
15
|
+
// primitives raw (see BigInt.nm) doesn't apply here.
|
|
11
16
|
func alloc = (ref self, int size, out int: out >= size) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
self
|
|
15
|
-
self->data = (unsigned long long)(unsigned int*)calloc(size, sizeof(unsigned int));
|
|
16
|
-
return self->cap;
|
|
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
|
-
```
|
|
17
|
+
self.cap = size
|
|
18
|
+
self.data = calloc(size, 4)
|
|
19
|
+
return self.cap
|
|
27
20
|
}
|
|
28
21
|
|
|
29
22
|
func grow = (ref self, int needed, out int: out >= needed) {
|
|
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
|
-
```
|
|
23
|
+
if self.cap >= needed {
|
|
24
|
+
return self.cap
|
|
25
|
+
}
|
|
26
|
+
var int new_cap = self.cap
|
|
27
|
+
if new_cap == 0 {
|
|
28
|
+
new_cap = 8
|
|
29
|
+
}
|
|
30
|
+
while new_cap < needed; new_cap *= 2 {}
|
|
31
|
+
self.data = realloc(self.data, new_cap * 4)
|
|
32
|
+
memset(self.data + self.cap * 4, 0, (new_cap - self.cap) * 4)
|
|
33
|
+
self.cap = new_cap
|
|
34
|
+
return self.cap
|
|
75
35
|
}
|
|
76
36
|
|
|
77
37
|
func zero = (ref self, int len) {
|
|
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
|
-
```
|
|
38
|
+
memset(self.data, 0, len * 4)
|
|
89
39
|
}
|
|
90
40
|
|
|
91
41
|
inline func load = (self, int i: i >= 0 && i < self.cap, out uint32) {
|
|
@@ -134,69 +84,24 @@ pub struct Buffer<T> {
|
|
|
134
84
|
}
|
|
135
85
|
|
|
136
86
|
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
|
-
```
|
|
87
|
+
self.cap = size
|
|
88
|
+
self.data = calloc(size, 8)
|
|
89
|
+
return self.cap
|
|
152
90
|
}
|
|
153
91
|
|
|
154
92
|
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
|
-
```
|
|
93
|
+
if self.cap >= needed {
|
|
94
|
+
return self.cap
|
|
95
|
+
}
|
|
96
|
+
var int new_cap = self.cap
|
|
97
|
+
if new_cap == 0 {
|
|
98
|
+
new_cap = 4
|
|
99
|
+
}
|
|
100
|
+
while new_cap < needed; new_cap *= 2 {}
|
|
101
|
+
self.data = realloc(self.data, new_cap * 8)
|
|
102
|
+
memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
|
|
103
|
+
self.cap = new_cap
|
|
104
|
+
return self.cap
|
|
200
105
|
}
|
|
201
106
|
|
|
202
107
|
inline func load_int = (self, int i: i >= 0 && i < self.cap, out int) {
|
|
@@ -267,17 +172,7 @@ pub struct Buffer<T> {
|
|
|
267
172
|
}
|
|
268
173
|
|
|
269
174
|
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
|
-
```
|
|
175
|
+
memset(self.data, 0, len * 8)
|
|
281
176
|
}
|
|
282
177
|
|
|
283
178
|
// T_SIZE-aware primitives for value-struct elements. Slab is sized in
|
|
@@ -286,74 +181,24 @@ pub struct Buffer<T> {
|
|
|
286
181
|
// reaching here is always a value type (primitive or struct).
|
|
287
182
|
|
|
288
183
|
func alloc_T = (ref self, int size, out int: out >= size) {
|
|
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
|
-
```
|
|
184
|
+
self.cap = size
|
|
185
|
+
self.data = calloc(size, T_SIZE)
|
|
186
|
+
return self.cap
|
|
304
187
|
}
|
|
305
188
|
|
|
306
189
|
func grow_T = (ref self, int needed, out int: out >= needed) {
|
|
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
|
-
```
|
|
190
|
+
if self.cap >= needed {
|
|
191
|
+
return self.cap
|
|
192
|
+
}
|
|
193
|
+
var int new_cap = self.cap
|
|
194
|
+
if new_cap == 0 {
|
|
195
|
+
new_cap = 4
|
|
196
|
+
}
|
|
197
|
+
while new_cap < needed; new_cap *= 2 {}
|
|
198
|
+
self.data = realloc(self.data, new_cap * T_SIZE)
|
|
199
|
+
memset(self.data + self.cap * T_SIZE, 0, (new_cap - self.cap) * T_SIZE)
|
|
200
|
+
self.cap = new_cap
|
|
201
|
+
return self.cap
|
|
357
202
|
}
|
|
358
203
|
|
|
359
204
|
// `inline` splices the (width-folded at monomorphization) raw body at
|
|
@@ -403,6 +248,12 @@ pub struct Buffer<T> {
|
|
|
403
248
|
```
|
|
404
249
|
}
|
|
405
250
|
|
|
251
|
+
// Store `val` into slot `i`, which MUST be fresh (calloc'd, or zeroed by
|
|
252
|
+
// move_T). For an owning T (string, or a struct with string fields) the
|
|
253
|
+
// specialised body deep-copies the incoming value but does NOT free the
|
|
254
|
+
// slot's previous occupant — a second `store_T` at an occupied index
|
|
255
|
+
// leaks it. To overwrite a live slot use replace_T (frees the displaced
|
|
256
|
+
// value) — this is the primitive every container's `set` uses.
|
|
406
257
|
inline func store_T = (ref self, int i: i >= 0 && i < self.cap, T val) {
|
|
407
258
|
```
|
|
408
259
|
#arch: c
|
|
@@ -650,18 +501,7 @@ pub struct Buffer<T> {
|
|
|
650
501
|
}
|
|
651
502
|
|
|
652
503
|
inline func zero_T = (ref self, int len) {
|
|
653
|
-
|
|
654
|
-
#arch: c
|
|
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
|
-
```
|
|
504
|
+
memset(self.data, 0, len * T_SIZE)
|
|
665
505
|
}
|
|
666
506
|
|
|
667
507
|
inline func store_or_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
|
|
@@ -681,21 +521,9 @@ pub struct Buffer<T> {
|
|
|
681
521
|
}
|
|
682
522
|
|
|
683
523
|
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
|
-
```
|
|
524
|
+
self.cap = size
|
|
525
|
+
self.data = calloc(size, 8)
|
|
526
|
+
return self.cap
|
|
699
527
|
}
|
|
700
528
|
|
|
701
529
|
inline func load_float = (self, int i: i >= 0 && i < self.cap, out float) {
|
|
@@ -727,20 +555,10 @@ pub struct Buffer<T> {
|
|
|
727
555
|
}
|
|
728
556
|
|
|
729
557
|
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
|
-
```
|
|
558
|
+
if self.data != 0 {
|
|
559
|
+
free(self.data)
|
|
560
|
+
}
|
|
561
|
+
self.data = 0
|
|
562
|
+
self.cap = 0
|
|
745
563
|
}
|
|
746
564
|
}
|
|
@@ -12,69 +12,35 @@ pub struct ClassBuffer<T> {
|
|
|
12
12
|
var cap = 0
|
|
13
13
|
|
|
14
14
|
func alloc_int = (ref self, int size, out int: out >= size) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
self
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```
|
|
15
|
+
self.cap = size
|
|
16
|
+
self.data = calloc(size, 8)
|
|
17
|
+
return self.cap
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Semantic parity with Buffer<T>.alloc_T: generic code (e.g. Map#init's
|
|
21
|
+
// `self.values.alloc_T(N)`) forwards to either Buffer — where alloc_T is
|
|
22
|
+
// T_SIZE-aware (string slots are 16 bytes) — or this ClassBuffer, whose
|
|
23
|
+
// slots are always one pointer wide. The compiler routes value-struct
|
|
24
|
+
// element types to Buffer and class/trait elements to ClassBuffer
|
|
25
|
+
// (monomorphize's field rewrite), so a call arriving HERE is always
|
|
26
|
+
// pointer-sized: delegate to alloc_int.
|
|
27
|
+
func alloc_T = (ref self, int size, out int: out >= size) {
|
|
28
|
+
return self.alloc_int(size)
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
func grow_int = (ref self, int needed, out int: out >= needed) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
int new_cap = self
|
|
37
|
-
if
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
self
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
#arch: aarch64
|
|
46
|
-
ldr x2, [x19, #16]
|
|
47
|
-
cmp x2, x1
|
|
48
|
-
b.ge .Lcb_grow_end
|
|
49
|
-
mov x3, #4
|
|
50
|
-
cmp x2, #0
|
|
51
|
-
csel x3, x3, x2, eq
|
|
52
|
-
cmp x3, x1
|
|
53
|
-
b.ge .Lcb_grow_got
|
|
54
|
-
.Lcb_grow_loop:
|
|
55
|
-
lsl x3, x3, #1
|
|
56
|
-
cmp x3, x1
|
|
57
|
-
b.lt .Lcb_grow_loop
|
|
58
|
-
.Lcb_grow_got:
|
|
59
|
-
sub sp, sp, #16
|
|
60
|
-
str x2, [sp, #0]
|
|
61
|
-
str x3, [sp, #8]
|
|
62
|
-
ldr x0, [x19, #8]
|
|
63
|
-
lsl x1, x3, #3
|
|
64
|
-
bl _realloc
|
|
65
|
-
str x0, [x19, #8]
|
|
66
|
-
ldr x2, [sp, #0]
|
|
67
|
-
ldr x3, [sp, #8]
|
|
68
|
-
add sp, sp, #16
|
|
69
|
-
str x3, [x19, #16]
|
|
70
|
-
add x0, x0, x2, lsl #3
|
|
71
|
-
mov x1, #0
|
|
72
|
-
sub x2, x3, x2
|
|
73
|
-
lsl x2, x2, #3
|
|
74
|
-
bl _memset
|
|
75
|
-
.Lcb_grow_end:
|
|
76
|
-
ldr x0, [x19, #16]
|
|
77
|
-
```
|
|
32
|
+
if self.cap >= needed {
|
|
33
|
+
return self.cap
|
|
34
|
+
}
|
|
35
|
+
var int new_cap = self.cap
|
|
36
|
+
if new_cap == 0 {
|
|
37
|
+
new_cap = 4
|
|
38
|
+
}
|
|
39
|
+
while new_cap < needed; new_cap *= 2 {}
|
|
40
|
+
self.data = realloc(self.data, new_cap * 8)
|
|
41
|
+
memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
|
|
42
|
+
self.cap = new_cap
|
|
43
|
+
return self.cap
|
|
78
44
|
}
|
|
79
45
|
|
|
80
46
|
inline func load_int = (self, int i: i >= 0 && i < self.cap, out int) {
|
|
@@ -99,51 +65,18 @@ pub struct ClassBuffer<T> {
|
|
|
99
65
|
// slots, matching _int.
|
|
100
66
|
|
|
101
67
|
func grow_T = (ref self, int needed, out int: out >= needed) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
int new_cap = self
|
|
106
|
-
if
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
self
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
#arch: aarch64
|
|
115
|
-
ldr x2, [x19, #16]
|
|
116
|
-
cmp x2, x1
|
|
117
|
-
b.ge .Lcb_grow_T_end
|
|
118
|
-
mov x3, #4
|
|
119
|
-
cmp x2, #0
|
|
120
|
-
csel x3, x3, x2, eq
|
|
121
|
-
cmp x3, x1
|
|
122
|
-
b.ge .Lcb_grow_T_got
|
|
123
|
-
.Lcb_grow_T_loop:
|
|
124
|
-
lsl x3, x3, #1
|
|
125
|
-
cmp x3, x1
|
|
126
|
-
b.lt .Lcb_grow_T_loop
|
|
127
|
-
.Lcb_grow_T_got:
|
|
128
|
-
sub sp, sp, #16
|
|
129
|
-
str x2, [sp, #0]
|
|
130
|
-
str x3, [sp, #8]
|
|
131
|
-
ldr x0, [x19, #8]
|
|
132
|
-
lsl x1, x3, #3
|
|
133
|
-
bl _realloc
|
|
134
|
-
str x0, [x19, #8]
|
|
135
|
-
ldr x2, [sp, #0]
|
|
136
|
-
ldr x3, [sp, #8]
|
|
137
|
-
add sp, sp, #16
|
|
138
|
-
str x3, [x19, #16]
|
|
139
|
-
add x0, x0, x2, lsl #3
|
|
140
|
-
mov x1, #0
|
|
141
|
-
sub x2, x3, x2
|
|
142
|
-
lsl x2, x2, #3
|
|
143
|
-
bl _memset
|
|
144
|
-
.Lcb_grow_T_end:
|
|
145
|
-
ldr x0, [x19, #16]
|
|
146
|
-
```
|
|
68
|
+
if self.cap >= needed {
|
|
69
|
+
return self.cap
|
|
70
|
+
}
|
|
71
|
+
var int new_cap = self.cap
|
|
72
|
+
if new_cap == 0 {
|
|
73
|
+
new_cap = 4
|
|
74
|
+
}
|
|
75
|
+
while new_cap < needed; new_cap *= 2 {}
|
|
76
|
+
self.data = realloc(self.data, new_cap * 8)
|
|
77
|
+
memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
|
|
78
|
+
self.cap = new_cap
|
|
79
|
+
return self.cap
|
|
147
80
|
}
|
|
148
81
|
|
|
149
82
|
inline func load_T = (self, int i: i >= 0 && i < self.cap, out T) {
|
|
@@ -160,6 +93,11 @@ pub struct ClassBuffer<T> {
|
|
|
160
93
|
```
|
|
161
94
|
}
|
|
162
95
|
|
|
96
|
+
// Store the owned class pointer `val` into slot `i`, which MUST be fresh
|
|
97
|
+
// (calloc'd, or zeroed by move_T/move_int). This is a plain pointer
|
|
98
|
+
// store — it does NOT destroy/free the slot's previous occupant, so a
|
|
99
|
+
// second `store_T` at an occupied index leaks that instance. Use
|
|
100
|
+
// replace_T (or replace_int) to overwrite a live slot.
|
|
163
101
|
inline func store_T = (ref self, int i: i >= 0 && i < self.cap, T val: val != 0) {
|
|
164
102
|
```
|
|
165
103
|
#arch: c
|
package/core/System/Map.nm
CHANGED
|
@@ -27,6 +27,9 @@ pub struct Map<TK: Hashable + Equatable, TV> {
|
|
|
27
27
|
pub func set = (ref self, move TK key, move TV value) {
|
|
28
28
|
var int cap = self.keys.cap
|
|
29
29
|
if cap == 0 {
|
|
30
|
+
// alloc_T: for Buffer<TK> it is T_SIZE-aware (string keys are
|
|
31
|
+
// 16-byte slots); for ClassBuffer<TV> it delegates to alloc_int
|
|
32
|
+
// (one pointer per slot). Both have it for generic parity.
|
|
30
33
|
cap = self.keys.alloc_T(8)
|
|
31
34
|
self.values.alloc_T(8)
|
|
32
35
|
self.used.alloc(8)
|