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/NOMEN_AGENTS.md
CHANGED
|
@@ -128,7 +128,13 @@ const y = x + 1 // Error: 'x' is null
|
|
|
128
128
|
|
|
129
129
|
### Visibility
|
|
130
130
|
|
|
131
|
-
`pub` exports
|
|
131
|
+
`pub` exports. `internal` is visible only within the declaring library/module
|
|
132
|
+
(the System library uses it to hide implementation details). Everything else is
|
|
133
|
+
private to its declaring scope.
|
|
134
|
+
|
|
135
|
+
`readonly` is a field-write modifier, not a visibility: the field reads at its
|
|
136
|
+
declared visibility but can only be assigned inside its declaring struct/class
|
|
137
|
+
(and its `extend`s). `const` fields are immutable everywhere.
|
|
132
138
|
|
|
133
139
|
### Imports
|
|
134
140
|
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// Arena<T>: a generational arena — one owner of every slot, with cheap
|
|
2
|
+
// copyable handles (`ArenaRef<T>`) instead of borrows. This is the single-ownership
|
|
3
|
+
// answer to "many places need to refer to the same node": the arena owns the
|
|
4
|
+
// values, everyone else holds `ArenaRef<T>` (a plain { index, generation } value
|
|
5
|
+
// that copies freely and never dangles undetected).
|
|
6
|
+
//
|
|
7
|
+
// Why not `List<T>` + raw `int` indices? An index silently aliases a recycled
|
|
8
|
+
// slot after a removal — the classic stale-index bug. An `ArenaRef<T>` carries the
|
|
9
|
+
// slot's generation, bumped on every `free`; a stale handle fails the
|
|
10
|
+
// generation check and `get` panics (`is_valid` / `get_or` test it without
|
|
11
|
+
// trapping), so use-after-free is DETECTED instead of silently reading
|
|
12
|
+
// another node.
|
|
13
|
+
//
|
|
14
|
+
// The arena is the sole owner: `free` relinquishes the slot's value (moved out
|
|
15
|
+
// and reclaimed by the ordinary ownership machinery) and bumps the generation;
|
|
16
|
+
// the arena's own #destroy reclaims every still-live slot at scope exit.
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A copyable, non-owning handle to an `Arena<T>` slot. The generation makes a
|
|
20
|
+
* reused slot distinguishable from the one this handle was issued for.
|
|
21
|
+
**/
|
|
22
|
+
pub struct ArenaRef<T> {
|
|
23
|
+
var int index = -1
|
|
24
|
+
var int generation = -1
|
|
25
|
+
|
|
26
|
+
pub func is_null = (self, out bool) {
|
|
27
|
+
return self.index < 0
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A generational arena: one owner of a set of `T` values, addressed by
|
|
33
|
+
* copyable `ArenaRef<T>` handles.
|
|
34
|
+
**/
|
|
35
|
+
pub struct Arena<T> {
|
|
36
|
+
// Slot payloads. T = value struct/primitive routes to Buffer<T>; T =
|
|
37
|
+
// class/trait routes to ClassBuffer<T> (monomorphize rewrites the field),
|
|
38
|
+
// so slot ownership follows the usual element rules.
|
|
39
|
+
var Buffer<T> values = Buffer<T>()
|
|
40
|
+
// Per-slot generation, bumped on every free. Slots are calloc'd, so a
|
|
41
|
+
// fresh slot's generation is 0.
|
|
42
|
+
var Buffer<int> generations = Buffer<int>()
|
|
43
|
+
// Freed slot indices available for reuse (LIFO free list). A raw Buffer
|
|
44
|
+
// plus an explicit count: a `List<int>` field would need its own
|
|
45
|
+
// monomorphization from inside a generic struct body.
|
|
46
|
+
var Buffer<int> free_indices = Buffer<int>()
|
|
47
|
+
var int free_count = 0
|
|
48
|
+
// High-water mark: every index < count has a slot (live or free).
|
|
49
|
+
var int count = 0
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* A fresh arena with no slots.
|
|
53
|
+
**/
|
|
54
|
+
pub func #init = (ref self) {
|
|
55
|
+
self.values = Buffer<T>()
|
|
56
|
+
self.generations = Buffer<int>()
|
|
57
|
+
self.free_indices = Buffer<int>()
|
|
58
|
+
self.free_count = 0
|
|
59
|
+
self.count = 0
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Store `value` in a slot (reusing a freed slot when one is available) and
|
|
64
|
+
* return a handle to it.
|
|
65
|
+
**/
|
|
66
|
+
pub func alloc = (ref self, move T value, out ArenaRef<T>) {
|
|
67
|
+
var int index = -1
|
|
68
|
+
if self.free_count > 0 {
|
|
69
|
+
// Reuse a freed slot. Its generation was already bumped by `free`,
|
|
70
|
+
// so stale handles to it are already invalid.
|
|
71
|
+
self.free_count = self.free_count - 1
|
|
72
|
+
index = self.free_indices.load_int(self.free_count)
|
|
73
|
+
} else {
|
|
74
|
+
index = self.count
|
|
75
|
+
self.count = index + 1
|
|
76
|
+
self.generations.grow_int(index + 1)
|
|
77
|
+
self.generations.store_int(index, 0)
|
|
78
|
+
}
|
|
79
|
+
self.values.grow(index + 1)
|
|
80
|
+
self.values.store(index, value)
|
|
81
|
+
var ArenaRef<T> handle = ArenaRef<T>()
|
|
82
|
+
handle.index = index
|
|
83
|
+
handle.generation = self.generations.load_int(index)
|
|
84
|
+
return handle
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Relinquish the slot `handle` points at (its value is reclaimed), bumping the
|
|
89
|
+
* generation so every outstanding handle to that slot becomes stale.
|
|
90
|
+
**/
|
|
91
|
+
pub func free = (ref self, ArenaRef<T> handle) {
|
|
92
|
+
if !self.is_valid(handle) {
|
|
93
|
+
panic("arena: free of a stale handle")
|
|
94
|
+
}
|
|
95
|
+
var T discarded = self.values.move(handle.index)
|
|
96
|
+
self.generations.store_int(handle.index, handle.generation + 1)
|
|
97
|
+
self.free_indices.grow_int(self.free_count + 1)
|
|
98
|
+
self.free_indices.store_int(self.free_count, handle.index)
|
|
99
|
+
self.free_count = self.free_count + 1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The current generation of a slot index (raw; for `ArenaRef` bookkeeping).
|
|
104
|
+
**/
|
|
105
|
+
pub func generation_of = (self, int index: index >= 0 && index < self.count, out int) {
|
|
106
|
+
return self.generations.load_int(index)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Whether `handle` still names a live slot.
|
|
111
|
+
**/
|
|
112
|
+
pub func is_valid = (self, ArenaRef<T> handle, out bool) {
|
|
113
|
+
if handle.index < 0 || handle.index >= self.count {
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
return self.generations.load_int(handle.index) == handle.generation
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The value `handle` names. Panics on a stale handle (use-after-free is a
|
|
121
|
+
* bug, not a case — use `is_valid` / `get_or` when absence is expected).
|
|
122
|
+
**/
|
|
123
|
+
pub func get = (self, ArenaRef<T> handle, out T) {
|
|
124
|
+
if !self.is_valid(handle) {
|
|
125
|
+
panic("arena: get of a stale handle")
|
|
126
|
+
}
|
|
127
|
+
return self.values.load(handle.index)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The value `handle` names, or `fallback` when the handle is stale.
|
|
132
|
+
**/
|
|
133
|
+
pub func get_or = (self, ArenaRef<T> handle, T fallback, out T) {
|
|
134
|
+
if !self.is_valid(handle) {
|
|
135
|
+
return fallback
|
|
136
|
+
}
|
|
137
|
+
return self.values.load(handle.index)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Replace the value `handle` names (same slot, same handle).
|
|
142
|
+
**/
|
|
143
|
+
pub func set = (ref self, ArenaRef<T> handle, move T value) {
|
|
144
|
+
if !self.is_valid(handle) {
|
|
145
|
+
panic("arena: set through a stale handle")
|
|
146
|
+
}
|
|
147
|
+
self.values.replace(handle.index, value)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The number of slots ever allocated (live + freed). Indices `0 .. count()`
|
|
152
|
+
* can be walked with `get_index`; freed slots return their stale value, so
|
|
153
|
+
* prefer `is_valid` + `get` when iterating handles.
|
|
154
|
+
**/
|
|
155
|
+
pub func count_all = (self, out int) {
|
|
156
|
+
return self.count
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Raw slot access by index — for iteration over the index space. Does not
|
|
161
|
+
* generation-check; callers own the index bookkeeping.
|
|
162
|
+
**/
|
|
163
|
+
pub func get_index = (self, int index: index >= 0 && index < self.count, out T) {
|
|
164
|
+
return self.values.load(index)
|
|
165
|
+
}
|
|
166
|
+
}
|
package/core/System/Array.nm
CHANGED
|
@@ -30,134 +30,40 @@ pub struct Array<T>: Viewable {
|
|
|
30
30
|
```
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
// Inline-storage element access — `unsafe` Nomen single-sourced for both
|
|
34
|
+
// backends (docs/CORE_RAW.md roadmap item 2). `self[index]` lowers to the
|
|
35
|
+
// element base each backend already uses for Array receivers (C skips the
|
|
36
|
+
// struct header; aarch64's receiver IS the first element).
|
|
33
37
|
pub inline func at = (self, int index: index >= 0 && index < self.length, out T) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return _data[index];
|
|
38
|
-
```
|
|
39
|
-
```
|
|
40
|
-
#arch: aarch64
|
|
41
|
-
// x19 = self (first elem), x1 = index, x8 = return buf for structs
|
|
42
|
-
mov x2, #T_SIZE
|
|
43
|
-
mul x1, x1, x2
|
|
44
|
-
cmp x2, #8
|
|
45
|
-
b.eq .L_at_8
|
|
46
|
-
b.gt .L_at_copy
|
|
47
|
-
cmp x2, #1
|
|
48
|
-
b.eq .L_at_1
|
|
49
|
-
cmp x2, #2
|
|
50
|
-
b.eq .L_at_2
|
|
51
|
-
ldr w0, [x19, x1]
|
|
52
|
-
b .L_at_end
|
|
53
|
-
.L_at_8:
|
|
54
|
-
ldr x0, [x19, x1]
|
|
55
|
-
b .L_at_end
|
|
56
|
-
.L_at_1:
|
|
57
|
-
ldrb w0, [x19, x1]
|
|
58
|
-
b .L_at_end
|
|
59
|
-
.L_at_2:
|
|
60
|
-
ldrh w0, [x19, x1]
|
|
61
|
-
b .L_at_end
|
|
62
|
-
// Struct element (T_SIZE > 8): copy the slot bytes into the x8
|
|
63
|
-
// sret buffer and return its address (Buffer.load_T convention).
|
|
64
|
-
.L_at_copy:
|
|
65
|
-
mov x0, x8
|
|
66
|
-
add x1, x19, x1
|
|
67
|
-
bl _memcpy
|
|
68
|
-
mov x0, x8
|
|
69
|
-
.L_at_end:
|
|
70
|
-
```
|
|
38
|
+
unsafe {
|
|
39
|
+
return self[index]
|
|
40
|
+
}
|
|
71
41
|
}
|
|
72
42
|
|
|
73
43
|
pub func first = (self: self.length > 0, out T) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return _data[0];
|
|
78
|
-
```
|
|
79
|
-
```
|
|
80
|
-
#arch: aarch64
|
|
81
|
-
// x19 = self (first elem), x8 = return buf for structs
|
|
82
|
-
mov x3, #T_SIZE
|
|
83
|
-
cmp x3, #8
|
|
84
|
-
b.eq .L_first_8
|
|
85
|
-
b.gt .L_first_copy
|
|
86
|
-
cmp x3, #1
|
|
87
|
-
b.eq .L_first_1
|
|
88
|
-
cmp x3, #2
|
|
89
|
-
b.eq .L_first_2
|
|
90
|
-
ldr w0, [x19]
|
|
91
|
-
b .L_first_end
|
|
92
|
-
.L_first_8:
|
|
93
|
-
ldr x0, [x19]
|
|
94
|
-
b .L_first_end
|
|
95
|
-
.L_first_1:
|
|
96
|
-
ldrb w0, [x19]
|
|
97
|
-
b .L_first_end
|
|
98
|
-
.L_first_2:
|
|
99
|
-
ldrh w0, [x19]
|
|
100
|
-
b .L_first_end
|
|
101
|
-
// Struct element (T_SIZE > 8): copy the first slot's bytes into
|
|
102
|
-
// the x8 sret buffer and return its address.
|
|
103
|
-
.L_first_copy:
|
|
104
|
-
mov x0, x8
|
|
105
|
-
mov x1, x19
|
|
106
|
-
mov x2, x3
|
|
107
|
-
bl _memcpy
|
|
108
|
-
mov x0, x8
|
|
109
|
-
.L_first_end:
|
|
110
|
-
```
|
|
44
|
+
unsafe {
|
|
45
|
+
return self[0]
|
|
46
|
+
}
|
|
111
47
|
}
|
|
112
48
|
|
|
49
|
+
// The string-slot specialization the raw `#if T_NEEDS_STRDUP` blocks used
|
|
50
|
+
// to express: T_NEEDS_STRDUP is a per-instantiation constant the
|
|
51
|
+
// monomorphizer substitutes (true for string, false otherwise) and folds,
|
|
52
|
+
// so each mono body keeps only its arm.
|
|
113
53
|
pub func set = (ref self, int index: index >= 0 && index < self.length, T value) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
```
|
|
129
|
-
#arch: aarch64
|
|
130
|
-
// x19 = self (first elem), x1 = index, x2 = value (address if struct)
|
|
131
|
-
mov x3, #T_SIZE
|
|
132
|
-
mul x1, x1, x3
|
|
133
|
-
cmp x3, #8
|
|
134
|
-
b.eq .L_set_8
|
|
135
|
-
b.gt .L_set_copy
|
|
136
|
-
cmp x3, #1
|
|
137
|
-
b.eq .L_set_1
|
|
138
|
-
cmp x3, #2
|
|
139
|
-
b.eq .L_set_2
|
|
140
|
-
str w2, [x19, x1]
|
|
141
|
-
b .L_set_done
|
|
142
|
-
.L_set_8:
|
|
143
|
-
str x2, [x19, x1]
|
|
144
|
-
b .L_set_done
|
|
145
|
-
.L_set_1:
|
|
146
|
-
strb w2, [x19, x1]
|
|
147
|
-
b .L_set_done
|
|
148
|
-
.L_set_2:
|
|
149
|
-
strh w2, [x19, x1]
|
|
150
|
-
b .L_set_done
|
|
151
|
-
// Struct element (T_SIZE > 8): x2 holds the ADDRESS of the value
|
|
152
|
-
// bytes — memcpy them into the slot (Buffer.store_T convention).
|
|
153
|
-
.L_set_copy:
|
|
154
|
-
mov x0, x19
|
|
155
|
-
add x0, x0, x1
|
|
156
|
-
mov x1, x2
|
|
157
|
-
mov x2, x3
|
|
158
|
-
bl _memcpy
|
|
159
|
-
.L_set_done:
|
|
160
|
-
```
|
|
54
|
+
unsafe {
|
|
55
|
+
if T_NEEDS_STRDUP {
|
|
56
|
+
// T is string: a fat value whose backing bytes must be
|
|
57
|
+
// heap-copied per slot — otherwise the slot would share the
|
|
58
|
+
// incoming pointer and auto_free would double-free it. Free
|
|
59
|
+
// the displaced slot's bytes (no local: a named copy would be
|
|
60
|
+
// auto-freed too), then store a fresh deep copy.
|
|
61
|
+
free((self[index] as ptr char) as uint64)
|
|
62
|
+
self[index] = strdup(value)
|
|
63
|
+
} else {
|
|
64
|
+
self[index] = value
|
|
65
|
+
}
|
|
66
|
+
}
|
|
161
67
|
}
|
|
162
68
|
|
|
163
69
|
// Bounds-checked accessors — the runtime-checked escape hatch for
|
|
@@ -181,46 +87,9 @@ pub struct Array<T>: Viewable {
|
|
|
181
87
|
}
|
|
182
88
|
|
|
183
89
|
pub func at_end = (self, out T) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return _data[self->length - 1];
|
|
188
|
-
```
|
|
189
|
-
```
|
|
190
|
-
#arch: aarch64
|
|
191
|
-
// x19 = self (first elem), length at [x19 - 8], x8 = return buf for structs
|
|
192
|
-
ldr x0, [x19, #-8]
|
|
193
|
-
sub x0, x0, #1
|
|
194
|
-
mov x1, #T_SIZE
|
|
195
|
-
mul x0, x0, x1
|
|
196
|
-
cmp x1, #8
|
|
197
|
-
b.eq .L_at_end_8
|
|
198
|
-
b.gt .L_at_end_copy
|
|
199
|
-
cmp x1, #1
|
|
200
|
-
b.eq .L_at_end_1
|
|
201
|
-
cmp x1, #2
|
|
202
|
-
b.eq .L_at_end_2
|
|
203
|
-
ldr w0, [x19, x0]
|
|
204
|
-
b .L_at_end_done
|
|
205
|
-
.L_at_end_8:
|
|
206
|
-
ldr x0, [x19, x0]
|
|
207
|
-
b .L_at_end_done
|
|
208
|
-
.L_at_end_1:
|
|
209
|
-
ldrb w0, [x19, x0]
|
|
210
|
-
b .L_at_end_done
|
|
211
|
-
.L_at_end_2:
|
|
212
|
-
ldrh w0, [x19, x0]
|
|
213
|
-
b .L_at_end_done
|
|
214
|
-
// Struct element (T_SIZE > 8): x0 = byte offset of the last slot —
|
|
215
|
-
// copy its bytes into the x8 sret buffer and return its address.
|
|
216
|
-
.L_at_end_copy:
|
|
217
|
-
mov x2, x1
|
|
218
|
-
add x1, x19, x0
|
|
219
|
-
mov x0, x8
|
|
220
|
-
bl _memcpy
|
|
221
|
-
mov x0, x8
|
|
222
|
-
.L_at_end_done:
|
|
223
|
-
```
|
|
90
|
+
unsafe {
|
|
91
|
+
return self[self.length - 1]
|
|
92
|
+
}
|
|
224
93
|
}
|
|
225
94
|
|
|
226
95
|
// A non-owning (ptr, len) slice [start, end) over self's inline element
|
package/core/System/BigInt.nm
CHANGED
|
@@ -6,7 +6,10 @@ pub struct BigInt {
|
|
|
6
6
|
var len = 0
|
|
7
7
|
var digits = Buffer<int>()
|
|
8
8
|
|
|
9
|
-
pub func
|
|
9
|
+
pub func #init = (ref self) {
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
pub func #init = (ref self, int val) {
|
|
10
13
|
self.sign = 1
|
|
11
14
|
var int v = val
|
|
12
15
|
if v < 0 {
|
|
@@ -17,68 +20,56 @@ pub struct BigInt {
|
|
|
17
20
|
self.digits.zero_int(self.digits.cap)
|
|
18
21
|
self.digits.store_int(0, v)
|
|
19
22
|
self.len = 1
|
|
20
|
-
return self
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
// Per-limb get/set stay raw: they are `inline` and splice into the limb
|
|
26
|
+
// loops, where the raw bodies are 1-2 instructions with no param
|
|
27
|
+
// marshalling. The unsafe-Nomen forms measured a 3x pidigits regression
|
|
28
|
+
// on aarch64 (the inline-method ABI parks self and spills locals per
|
|
29
|
+
// splice); the C backend (single TU, -O2) showed no difference either
|
|
30
|
+
// way, so the raw blocks win on single-sourcing grounds being equal.
|
|
31
|
+
// See docs/CORE_RAW.md "unsafe outcomes".
|
|
23
32
|
inline func get = (self, int i, out uint64) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
#arch: aarch64
|
|
30
|
-
ldr x0, [x0, #32]
|
|
31
|
-
ldr x0, [x0, x1, lsl #3]
|
|
32
|
-
```
|
|
33
|
+
unsafe {
|
|
34
|
+
var ptr uint64 limbs = self.digits.data as ptr uint64
|
|
35
|
+
return limbs[i]
|
|
36
|
+
}
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
inline func set = (ref self, int i, uint64 val) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
#arch: aarch64
|
|
42
|
-
ldr x0, [x19, #32]
|
|
43
|
-
str x2, [x0, x1, lsl #3]
|
|
44
|
-
```
|
|
40
|
+
unsafe {
|
|
41
|
+
var ptr uint64 limbs = self.digits.data as ptr uint64
|
|
42
|
+
limbs[i] = val
|
|
43
|
+
}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
// Raw data-pointer accessors. The limb loops below hoist `digits.data`
|
|
48
47
|
// into a local once (before the loop) and index through it via get_at /
|
|
49
48
|
// set_at, so each limb access is a single strided load/store instead of
|
|
50
49
|
// re-reading self->digits.data every iteration. ptr is held in a uint64.
|
|
50
|
+
// All five stay raw: measured on aarch64, even the loop-hoisted
|
|
51
|
+
// data_ptr as Nomen cost pidigits ~30% (the inline splice perturbs the
|
|
52
|
+
// whole-function asm plan); the C backend was identical either way.
|
|
53
|
+
// See docs/CORE_RAW.md "unsafe outcomes".
|
|
51
54
|
inline func data_ptr = (self, out uint64) {
|
|
52
|
-
|
|
53
|
-
#arch: c
|
|
54
|
-
return (unsigned long long)self->digits.data;
|
|
55
|
-
```
|
|
56
|
-
```
|
|
57
|
-
#arch: aarch64
|
|
58
|
-
ldr x0, [x0, #32]
|
|
59
|
-
```
|
|
55
|
+
return self.digits.data
|
|
60
56
|
}
|
|
61
57
|
|
|
58
|
+
// Same story as get/set above: the hoisted-pointer limb accessors stay
|
|
59
|
+
// raw for the aarch64 splice path. `data_ptr` is called once per loop
|
|
60
|
+
// (to hoist the slab address), so its Nomen body is free.
|
|
62
61
|
inline func get_at = (self, uint64 ptr, int i, out uint64) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```
|
|
68
|
-
#arch: aarch64
|
|
69
|
-
ldr x0, [x1, x2, lsl #3]
|
|
70
|
-
```
|
|
62
|
+
unsafe {
|
|
63
|
+
var ptr uint64 limbs = ptr as ptr uint64
|
|
64
|
+
return limbs[i]
|
|
65
|
+
}
|
|
71
66
|
}
|
|
72
67
|
|
|
73
68
|
inline func set_at = (ref self, uint64 ptr, int i, uint64 val) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
#arch: aarch64
|
|
80
|
-
str x3, [x1, x2, lsl #3]
|
|
81
|
-
```
|
|
69
|
+
unsafe {
|
|
70
|
+
var ptr uint64 limbs = ptr as ptr uint64
|
|
71
|
+
limbs[i] = val
|
|
72
|
+
}
|
|
82
73
|
}
|
|
83
74
|
|
|
84
75
|
func ensure = (ref self, int needed) {
|
|
@@ -539,20 +530,8 @@ pub struct BigInt {
|
|
|
539
530
|
}
|
|
540
531
|
self.len = self.len - 1
|
|
541
532
|
}
|
|
542
|
-
|
|
543
|
-
a0.digits.destroy()
|
|
544
|
-
a1.digits.destroy()
|
|
545
|
-
b0.digits.destroy()
|
|
546
|
-
b1.digits.destroy()
|
|
547
|
-
z0.digits.destroy()
|
|
548
|
-
z2.digits.destroy()
|
|
549
|
-
aa.digits.destroy()
|
|
550
|
-
bb.digits.destroy()
|
|
551
|
-
z1.digits.destroy()
|
|
552
|
-
s0.digits.destroy()
|
|
553
|
-
s1.digits.destroy()
|
|
554
|
-
s2.digits.destroy()
|
|
555
533
|
}
|
|
534
|
+
|
|
556
535
|
// self = quotient, a = dividend, b = divisor, remainder = remainder
|
|
557
536
|
// Uses remainder's internal buffer as working space
|
|
558
537
|
pub func div_to = (ref self, BigInt a, BigInt b, ref BigInt remainder) {
|