mt-lang 0.3.1 → 0.3.4

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.
data/std/iter.mt ADDED
@@ -0,0 +1,304 @@
1
+ ## std.iter — composable, lazy iteration adaptors.
2
+ ##
3
+ ## Each source/adaptor creates heap-allocated state linked through
4
+ ## function pointers. Release walks the chain to free all allocations.
5
+ ## Callbacks use fn types (function pointers, no captures).
6
+ ##
7
+ ## iter_map stores the mapped value inline in the adaptor state and
8
+ ## returns a pointer to it — no per-item allocation.
9
+ ##
10
+ ## Usage:
11
+ ## import std.iter
12
+ ## let it = iter.from_array(ref_of(arr))
13
+ ## let it2 = iter.iter_filter(it, pred)
14
+ ## let v = iter.collect_vec(it2)
15
+
16
+ import std.mem.heap as heap
17
+ import std.mem.ptr as ptr
18
+ import std.vec as v
19
+
20
+ ## ── Core Iter type ───────────────────────────────────────────────────
21
+
22
+ struct Iter[T]:
23
+ state: ptr[void]
24
+ next_fn: fn(state: ptr[void]) -> ptr[T]?
25
+ release_fn: fn(state: ptr[void]) -> void
26
+
27
+ ## ── Ownership helpers ────────────────────────────────────────────────
28
+
29
+ public function own_to_ptr[T](owned: own[T]) -> ptr[void]:
30
+ return unsafe: ptr[void]<-owned
31
+
32
+ ## ── Source: Vec ─────────────────────────────────────────────────────
33
+
34
+ public function from_vec[T](vec: ref[v.Vec[T]]) -> Iter[T]:
35
+ return from_span(vec.as_span())
36
+
37
+ ## ── Source: array ────────────────────────────────────────────────────
38
+
39
+ public function from_array[T, N](arr: ref[array[T, N]]) -> Iter[T]:
40
+ return from_span(arr.as_span())
41
+
42
+ ## ── .as_iter() extending blocks ──────────────────────────────────────
43
+
44
+ extending v.Vec[T]:
45
+ public editable function as_iter() -> Iter[T]:
46
+ return from_vec(ref_of(this))
47
+
48
+ extending array[T, N]:
49
+ public editable function as_iter() -> Iter[T]:
50
+ return from_array[T, N](ref_of(this))
51
+
52
+ extending span[T]:
53
+ public function as_iter() -> Iter[T]:
54
+ return from_span(this)
55
+
56
+ ## ── Source: span ─────────────────────────────────────────────────────
57
+
58
+ struct SpanIterState[T]:
59
+ sp: span[T]
60
+ index: ptr_uint
61
+
62
+ public function span_advance[T](state: ptr[void]) -> ptr[T]?:
63
+ let s = unsafe: ptr[SpanIterState[T]]<-state
64
+ let _this = unsafe: read(s)
65
+ if _this.index >= _this.sp.len:
66
+ return null
67
+ let item = unsafe: _this.sp.data + _this.index
68
+ unsafe: read(s).index += 1
69
+ return item
70
+
71
+ public function span_release[T](state: ptr[void]) -> void:
72
+ let s = unsafe: ptr[SpanIterState[T]]<-state
73
+ heap.release[SpanIterState[T]](s)
74
+
75
+ public function from_span[T](sp: span[T]) -> Iter[T]:
76
+ let state = heap.must_alloc[SpanIterState[T]](1)
77
+ state.index = 0
78
+ state.sp = sp
79
+ let p = own_to_ptr(state)
80
+ return Iter[T](state = p, next_fn = span_advance[T], release_fn = span_release[T])
81
+
82
+ ## ── Adaptor: Filter ──────────────────────────────────────────────────
83
+
84
+ struct FilterState[T]:
85
+ inner: Iter[T]
86
+ pred: fn(value: T) -> bool
87
+
88
+ public function filter_advance[T](state: ptr[void]) -> ptr[T]?:
89
+ let s = unsafe: ptr[FilterState[T]]<-state
90
+ let _this = unsafe: read(s)
91
+ var item = _this.inner.next_fn(_this.inner.state)
92
+ while item != null:
93
+ if _this.pred(item.load()):
94
+ return item
95
+ item = _this.inner.next_fn(_this.inner.state)
96
+ return null
97
+
98
+ public function filter_release[T](state: ptr[void]) -> void:
99
+ let s = unsafe: ptr[FilterState[T]]<-state
100
+ let _this = unsafe: read(s)
101
+ _this.inner.release_fn(_this.inner.state)
102
+ heap.release[FilterState[T]](s)
103
+
104
+ public function iter_filter[T](iter: Iter[T], pred: fn(value: T) -> bool) -> Iter[T]:
105
+ let state = heap.must_alloc[FilterState[T]](1)
106
+ state.inner = iter
107
+ state.pred = pred
108
+ let p = own_to_ptr(state)
109
+ return Iter[T](state = p, next_fn = filter_advance[T], release_fn = filter_release[T])
110
+
111
+ ## ── Adaptor: Map ─────────────────────────────────────────────────────
112
+
113
+ struct MapState[T, U]:
114
+ inner: Iter[T]
115
+ map_fn: fn(value: T) -> U
116
+ current: U
117
+
118
+ public function map_advance[T, U](state: ptr[void]) -> ptr[U]?:
119
+ let s = unsafe: ptr[MapState[T, U]]<-state
120
+ let current_offset = offset_of(MapState[T, U], current)
121
+ let p = unsafe: read(s)
122
+ let item = p.inner.next_fn(p.inner.state) else:
123
+ return null
124
+ let base: ptr[ubyte] = unsafe: ptr[ubyte]<-s
125
+ let field_ptr = unsafe: base + ptr_uint<-current_offset
126
+ let target: ptr[U] = unsafe: ptr[U]<-field_ptr
127
+ target.store(p.map_fn(item.load()))
128
+ return target
129
+
130
+ public function map_release[T, U](state: ptr[void]) -> void:
131
+ let s = unsafe: ptr[MapState[T, U]]<-state
132
+ let _this = unsafe: read(s)
133
+ _this.inner.release_fn(_this.inner.state)
134
+ heap.release[MapState[T, U]](s)
135
+
136
+ public function iter_map[T, U](iter: Iter[T], f: fn(value: T) -> U) -> Iter[U]:
137
+ let state = heap.must_alloc[MapState[T, U]](1)
138
+ state.inner = iter
139
+ state.map_fn = f
140
+ let p = own_to_ptr(state)
141
+ return Iter[U](state = p, next_fn = map_advance[T, U], release_fn = map_release[T, U])
142
+
143
+ ## ── Adaptor: Take ────────────────────────────────────────────────────
144
+
145
+ struct TakeState[T]:
146
+ inner: Iter[T]
147
+ remaining: int
148
+
149
+ public function take_advance[T](state: ptr[void]) -> ptr[T]?:
150
+ let s = unsafe: ptr[TakeState[T]]<-state
151
+ let _this = unsafe: read(s)
152
+ if _this.remaining <= 0:
153
+ return null
154
+ unsafe: read(s).remaining -= 1
155
+ return _this.inner.next_fn(_this.inner.state)
156
+
157
+ public function take_release[T](state: ptr[void]) -> void:
158
+ let s = unsafe: ptr[TakeState[T]]<-state
159
+ let _this = unsafe: read(s)
160
+ _this.inner.release_fn(_this.inner.state)
161
+ heap.release[TakeState[T]](s)
162
+
163
+ public function iter_take[T](iter: Iter[T], n: int) -> Iter[T]:
164
+ let state = heap.must_alloc[TakeState[T]](1)
165
+ state.inner = iter
166
+ state.remaining = n
167
+ let p = own_to_ptr(state)
168
+ return Iter[T](state = p, next_fn = take_advance[T], release_fn = take_release[T])
169
+
170
+ ## ── Adaptor: Skip ────────────────────────────────────────────────────
171
+
172
+ struct SkipState[T]:
173
+ inner: Iter[T]
174
+ skip_count: int
175
+
176
+ public function skip_advance[T](state: ptr[void]) -> ptr[T]?:
177
+ let s = unsafe: ptr[SkipState[T]]<-state
178
+ let _this = unsafe: read(s)
179
+ while _this.skip_count > 0:
180
+ let _ = _this.inner.next_fn(_this.inner.state) else:
181
+ return null
182
+ unsafe: read(s).skip_count -= 1
183
+ return _this.inner.next_fn(_this.inner.state)
184
+
185
+ public function skip_release[T](state: ptr[void]) -> void:
186
+ let s = unsafe: ptr[SkipState[T]]<-state
187
+ let _this = unsafe: read(s)
188
+ _this.inner.release_fn(_this.inner.state)
189
+ heap.release[SkipState[T]](s)
190
+
191
+ public function iter_skip[T](iter: Iter[T], n: int) -> Iter[T]:
192
+ let state = heap.must_alloc[SkipState[T]](1)
193
+ state.inner = iter
194
+ state.skip_count = n
195
+ let p = own_to_ptr(state)
196
+ return Iter[T](state = p, next_fn = skip_advance[T], release_fn = skip_release[T])
197
+
198
+ ## ── Adaptor: Enumerate ────────────────────────────────────────────────
199
+
200
+ struct Enumerated[T]:
201
+ index: ptr_uint
202
+ value: T
203
+
204
+ struct EnumerateState[T]:
205
+ inner: Iter[T]
206
+ index: ptr_uint
207
+ current: Enumerated[T]
208
+
209
+ public function enum_advance[T](state: ptr[void]) -> ptr[Enumerated[T]]?:
210
+ let s = unsafe: ptr[EnumerateState[T]]<-state
211
+ let current_offset = offset_of(EnumerateState[T], current)
212
+ let p = unsafe: read(s)
213
+ let item = p.inner.next_fn(p.inner.state) else:
214
+ return null
215
+ let base: ptr[ubyte] = unsafe: ptr[ubyte]<-s
216
+ let field_ptr = unsafe: base + ptr_uint<-current_offset
217
+ let target: ptr[Enumerated[T]] = unsafe: ptr[Enumerated[T]]<-field_ptr
218
+ target.store(Enumerated[T](index = p.index, value = item.load()))
219
+ unsafe: read(s).index += 1
220
+ return target
221
+
222
+ public function enum_release[T](state: ptr[void]) -> void:
223
+ let s = unsafe: ptr[EnumerateState[T]]<-state
224
+ let _this = unsafe: read(s)
225
+ _this.inner.release_fn(_this.inner.state)
226
+ heap.release[EnumerateState[T]](s)
227
+
228
+ public function iter_enumerate[T](iter: Iter[T]) -> Iter[Enumerated[T]]:
229
+ let state = heap.must_alloc[EnumerateState[T]](1)
230
+ state.inner = iter
231
+ state.index = 0
232
+ let p = own_to_ptr(state)
233
+ let enum_it = Iter[Enumerated[T]](state = p, next_fn = enum_advance[T], release_fn = enum_release[T])
234
+ return enum_it
235
+
236
+ ## ── Consumer: Fold ───────────────────────────────────────────────────
237
+
238
+ public function iter_fold[T, U](iter: Iter[T], init: U, f: fn(accum: U, value: T) -> U) -> U:
239
+ var accum = init
240
+ var item = iter.next_fn(iter.state)
241
+ while item != null:
242
+ accum = f(accum, item.load())
243
+ item = iter.next_fn(iter.state)
244
+ iter.release_fn(iter.state)
245
+ return accum
246
+
247
+ ## ── Consumer: Find ───────────────────────────────────────────────────
248
+
249
+ public function iter_find[T](iter: Iter[T], pred: fn(value: T) -> bool) -> Option[T]:
250
+ var item = iter.next_fn(iter.state)
251
+ while item != null:
252
+ if pred(item.load()):
253
+ let val = item.load()
254
+ iter.release_fn(iter.state)
255
+ return Option[T].some(value = val)
256
+ item = iter.next_fn(iter.state)
257
+ iter.release_fn(iter.state)
258
+ return Option[T].none
259
+
260
+ ## ── Consumer: Any ────────────────────────────────────────────────────
261
+
262
+ public function iter_any[T](iter: Iter[T], pred: fn(value: T) -> bool) -> bool:
263
+ var item = iter.next_fn(iter.state)
264
+ while item != null:
265
+ if pred(item.load()):
266
+ iter.release_fn(iter.state)
267
+ return true
268
+ item = iter.next_fn(iter.state)
269
+ iter.release_fn(iter.state)
270
+ return false
271
+
272
+ ## ── Consumer: All ────────────────────────────────────────────────────
273
+
274
+ public function iter_all[T](iter: Iter[T], pred: fn(value: T) -> bool) -> bool:
275
+ var item = iter.next_fn(iter.state)
276
+ while item != null:
277
+ if not pred(item.load()):
278
+ iter.release_fn(iter.state)
279
+ return false
280
+ item = iter.next_fn(iter.state)
281
+ iter.release_fn(iter.state)
282
+ return true
283
+
284
+ ## ── Consumer: Count ──────────────────────────────────────────────────
285
+
286
+ public function iter_count[T](iter: Iter[T]) -> ptr_uint:
287
+ var count: ptr_uint = 0
288
+ var item = iter.next_fn(iter.state)
289
+ while item != null:
290
+ count += 1
291
+ item = iter.next_fn(iter.state)
292
+ iter.release_fn(iter.state)
293
+ return count
294
+
295
+ ## ── Collect: Vec ─────────────────────────────────────────────────────
296
+
297
+ public function collect_vec[T](iter: Iter[T]) -> v.Vec[T]:
298
+ var result = v.Vec[T].create()
299
+ var item = iter.next_fn(iter.state)
300
+ while item != null:
301
+ result.push(item.load())
302
+ item = iter.next_fn(iter.state)
303
+ iter.release_fn(iter.state)
304
+ return result
data/std/mem/ptr.mt ADDED
@@ -0,0 +1,12 @@
1
+ ## Pointer load/store — safe wrappers around unsafe: read(ptr).
2
+ ##
3
+ ## import std.mem.ptr as ptr
4
+ ## p.store(42)
5
+ ## let v = p.load()
6
+
7
+ extending ptr[T]:
8
+ public function load() -> T:
9
+ return unsafe: read(this)
10
+
11
+ public function store(value: T) -> void:
12
+ unsafe: read(this) = value
data/std/noise.mt ADDED
@@ -0,0 +1,201 @@
1
+ ## Coherent noise generation — Perlin noise and fractal variants.
2
+ ##
3
+ ## Seed-based deterministic noise for procedural generation:
4
+ ## terrain, textures, fog, animation, and more.
5
+ ##
6
+ ## import std.noise as ns
7
+ ## var noise = ns.Noise.create(42)
8
+ ## let h = noise.fbm2d(x * 0.01, y * 0.01)
9
+
10
+
11
+ public struct Noise:
12
+ perm: array[ubyte, 512]
13
+ octaves: int
14
+ lacunarity: float
15
+ gain: float
16
+ frequency: float
17
+
18
+
19
+ # ── fade / interpolation ──
20
+
21
+ function fade(t: float) -> float:
22
+ return t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
23
+
24
+
25
+ function lerp(a: float, b: float, t: float) -> float:
26
+ return a + t * (b - a)
27
+
28
+
29
+ # ── gradient functions ──
30
+
31
+ function grad2d(hash: int, x: float, y: float) -> float:
32
+ let h = hash & 3
33
+ let u = if h == 0 or h == 1: x else: y
34
+ let v = if h == 0 or h == 3: y else: x
35
+ return (if (h & 1) == 0: u else: -u) + (if (h & 2) == 0: v else: -v)
36
+
37
+
38
+ function grad3d(hash: int, x: float, y: float, z: float) -> float:
39
+ let h = hash & 15
40
+ let u = if h < 8: x else: y
41
+ let v = if h < 4: y else: if h == 12 or h == 14: x else: z
42
+ let mu = if (h & 1) == 0: u else: -u
43
+ let mv = if (h & 2) == 0: v else: -v
44
+ return mu + mv
45
+
46
+
47
+ # ── internal noise functions ──
48
+
49
+ function perlin2d_impl(perm: array[ubyte, 512], x: float, y: float) -> float:
50
+ let ix = int<-(x)
51
+ let iy = int<-(y)
52
+ let X = ix & 255
53
+ let Y = iy & 255
54
+ let xf = x - float<-(ix - (ix & ~255))
55
+ let yf = y - float<-(iy - (iy & ~255))
56
+
57
+ let u = fade(if xf < 0.0: xf + 1.0 else: xf)
58
+ let v = fade(if yf < 0.0: yf + 1.0 else: yf)
59
+
60
+ let A = int<-(perm[X]) + Y
61
+ let B = int<-(perm[X + 1]) + Y
62
+ let aa = int<-(perm[A])
63
+ let ab = int<-(perm[A + 1])
64
+ let ba = int<-(perm[B])
65
+ let bb = int<-(perm[B + 1])
66
+
67
+ let x1 = lerp(grad2d(aa, xf, yf), grad2d(ba, xf - 1.0, yf), u)
68
+ let x2 = lerp(grad2d(ab, xf, yf - 1.0), grad2d(bb, xf - 1.0, yf - 1.0), u)
69
+
70
+ return lerp(x1, x2, v)
71
+
72
+
73
+ function perlin3d_impl(perm: array[ubyte, 512], x: float, y: float, z: float) -> float:
74
+ let ix = int<-(x)
75
+ let iy = int<-(y)
76
+ let iz = int<-(z)
77
+ let X = ix & 255
78
+ let Y = iy & 255
79
+ let Z = iz & 255
80
+ let xf = x - float<-(ix - (ix & ~255))
81
+ let yf = y - float<-(iy - (iy & ~255))
82
+ let zf = z - float<-(iz - (iz & ~255))
83
+
84
+ let u = fade(if xf < 0.0: xf + 1.0 else: xf)
85
+ let v = fade(if yf < 0.0: yf + 1.0 else: yf)
86
+ let w = fade(if zf < 0.0: zf + 1.0 else: zf)
87
+
88
+ let A = int<-(perm[X]) + Y
89
+ let AA = int<-(perm[A]) + Z
90
+ let AB = int<-(perm[A + 1]) + Z
91
+ let B = int<-(perm[X + 1]) + Y
92
+ let BA = int<-(perm[B]) + Z
93
+ let BB = int<-(perm[B + 1]) + Z
94
+
95
+ let x1 = lerp(grad3d(int<-(perm[AA]), xf, yf, zf), grad3d(int<-(perm[BA]), xf - 1.0, yf, zf), u)
96
+ let x2 = lerp(grad3d(int<-(perm[AB]), xf, yf - 1.0, zf), grad3d(int<-(perm[BB]), xf - 1.0, yf - 1.0, zf), u)
97
+ let y1 = lerp(x1, x2, v)
98
+
99
+ let x3 = lerp(grad3d(int<-(perm[AA + 1]), xf, yf, zf - 1.0), grad3d(int<-(perm[BA + 1]), xf - 1.0, yf, zf - 1.0), u)
100
+ let x4 = lerp(grad3d(int<-(perm[AB + 1]), xf, yf - 1.0, zf - 1.0), grad3d(int<-(perm[BB + 1]), xf - 1.0, yf - 1.0, zf - 1.0), u)
101
+ let y2 = lerp(x3, x4, v)
102
+
103
+ return lerp(y1, y2, w)
104
+
105
+
106
+ # ── float floor for negative numbers ──
107
+
108
+ function floor_f(x: float) -> int:
109
+ let i = int<-(x)
110
+ if x < 0.0 and float<-(i) != x:
111
+ return i - 1
112
+ return i
113
+
114
+
115
+ # ── public API ──
116
+
117
+ extending Noise:
118
+ public static function create(seed: ulong) -> Noise:
119
+ var n = Noise(
120
+ perm = zero[array[ubyte, 512]],
121
+ octaves = 6,
122
+ lacunarity = 2.0,
123
+ gain = 0.5,
124
+ frequency = 1.0
125
+ )
126
+
127
+ var i: int = 0
128
+ while i < 256:
129
+ n.perm[i] = ubyte<-i
130
+ i += 1
131
+
132
+ var state: ulong = seed
133
+ var j: int = 255
134
+ while j > 0:
135
+ state = state * 6364136223846793005 + 1442695040888963407
136
+ let r = int<-(state % ulong<-(j + 1))
137
+ let tmp = n.perm[j]
138
+ n.perm[j] = n.perm[r]
139
+ n.perm[r] = tmp
140
+ j -= 1
141
+
142
+ i = 0
143
+ while i < 256:
144
+ n.perm[i + 256] = n.perm[i]
145
+ i += 1
146
+
147
+ return n
148
+
149
+
150
+ public function perlin2d(x: float, y: float) -> float:
151
+ return perlin2d_impl(this.perm, x, y)
152
+
153
+
154
+ public function perlin3d(x: float, y: float, z: float) -> float:
155
+ return perlin3d_impl(this.perm, x, y, z)
156
+
157
+
158
+ public function fbm2d(x: float, y: float) -> float:
159
+ var value: float = 0.0
160
+ var freq: float = this.frequency
161
+ var amp: float = 1.0
162
+ var max_val: float = 0.0
163
+ var i: int = 0
164
+ while i < this.octaves:
165
+ value = value + amp * perlin2d_impl(this.perm, x * freq, y * freq)
166
+ max_val = max_val + amp
167
+ amp = amp * this.gain
168
+ freq = freq * this.lacunarity
169
+ i += 1
170
+ return value / max_val
171
+
172
+
173
+ public function fbm3d(x: float, y: float, z: float) -> float:
174
+ var value: float = 0.0
175
+ var freq: float = this.frequency
176
+ var amp: float = 1.0
177
+ var max_val: float = 0.0
178
+ var i: int = 0
179
+ while i < this.octaves:
180
+ value = value + amp * perlin3d_impl(this.perm, x * freq, y * freq, z * freq)
181
+ max_val = max_val + amp
182
+ amp = amp * this.gain
183
+ freq = freq * this.lacunarity
184
+ i += 1
185
+ return value / max_val
186
+
187
+
188
+ public editable function set_octaves(n: int) -> void:
189
+ this.octaves = n
190
+
191
+
192
+ public editable function set_lacunarity(v: float) -> void:
193
+ this.lacunarity = v
194
+
195
+
196
+ public editable function set_gain(v: float) -> void:
197
+ this.gain = v
198
+
199
+
200
+ public editable function set_frequency(v: float) -> void:
201
+ this.frequency = v
data/std/pool.mt ADDED
@@ -0,0 +1,82 @@
1
+ ## Object pool — fixed-capacity reusable object storage.
2
+ ##
3
+ ## Pre-allocate objects once, then acquire/release without
4
+ ## allocation churn. O(1) acquire and release via free stack.
5
+ ##
6
+ ## import std.pool as pool
7
+ ## var p = pool.Pool[Bullet].create(64)
8
+ ## let id = p.acquire() else: /* pool exhausted */
9
+ ## let bullet = p.get(id) # ptr to object
10
+ ## p.release(id)
11
+
12
+ import std.vec as vec
13
+ import std.mem.heap as heap
14
+
15
+
16
+ public struct Pool[T]:
17
+ objects: ptr[T]
18
+ free_stack: vec.Vec[ptr_uint]
19
+ capacity: ptr_uint
20
+
21
+
22
+ # ── public API ──
23
+
24
+ extending Pool[T]:
25
+ public static function create(capacity: ptr_uint) -> Pool[T]:
26
+ var p = Pool[T](
27
+ objects = heap.must_alloc[T](capacity),
28
+ free_stack = vec.Vec[ptr_uint].with_capacity(capacity),
29
+ capacity = capacity
30
+ )
31
+
32
+ # Push all indices onto the free stack in reverse order so
33
+ # acquire() returns them in ascending order (0 first).
34
+ var i = capacity
35
+ while i > 0:
36
+ i -= 1
37
+ p.free_stack.push(i)
38
+
39
+ return p
40
+
41
+
42
+ public editable function acquire() -> Option[ptr_uint]:
43
+ let idx = this.free_stack.pop() else:
44
+ return Option[ptr_uint].none
45
+ return Option[ptr_uint].some(value = idx)
46
+
47
+
48
+ public function get(index: ptr_uint) -> ptr[T]?:
49
+ if index >= this.capacity:
50
+ return null
51
+ unsafe:
52
+ return this.objects + index
53
+
54
+
55
+ public editable function release_object(index: ptr_uint) -> void:
56
+ if index >= this.capacity:
57
+ return
58
+
59
+ # Check for double-release by scanning free stack.
60
+ # Skip this check for simplicity — caller must not double-release.
61
+ this.free_stack.push(index)
62
+
63
+
64
+ public function available() -> ptr_uint:
65
+ return this.free_stack.len()
66
+
67
+
68
+ public function count() -> ptr_uint:
69
+ return this.capacity - this.free_stack.len()
70
+
71
+
72
+ public editable function clear() -> void:
73
+ this.free_stack.clear()
74
+ var i = this.capacity
75
+ while i > 0:
76
+ i -= 1
77
+ this.free_stack.push(i)
78
+
79
+
80
+ public editable function release() -> void:
81
+ this.free_stack.release()
82
+ heap.release(this.objects)
data/std/signal.mt ADDED
@@ -0,0 +1,66 @@
1
+ ## Signal — fixed-capacity observer / publish-subscribe.
2
+ ##
3
+ ## Connect callbacks to signals and fire typed payloads.
4
+ ## Up to 16 subscribers per signal, stack-allocated.
5
+ ##
6
+ ## import std.signal as sig
7
+ ## var on_damage = sig.Signal[int].create()
8
+ ## on_damage.connect(handle_damage)
9
+ ## on_damage.fire(25)
10
+
11
+ public struct Signal[Payload]:
12
+ slots: array[fn(payload: Payload) -> void, 16]
13
+ count: ptr_uint
14
+
15
+
16
+ # ── public API ──
17
+
18
+ extending Signal[Payload]:
19
+ public static function create() -> Signal[Payload]:
20
+ var s = Signal[Payload](
21
+ slots = zero[array[fn(payload: Payload) -> void, 16]],
22
+ count = 0
23
+ )
24
+ return s
25
+
26
+
27
+ public editable function connect(callback: fn(payload: Payload) -> void) -> void:
28
+ if this.count >= 16:
29
+ return
30
+
31
+ var i: ptr_uint = 0
32
+ while i < this.count:
33
+ unsafe:
34
+ if this.slots[i] == callback:
35
+ return
36
+ i += 1
37
+
38
+ unsafe:
39
+ this.slots[this.count] = callback
40
+ this.count = this.count + 1
41
+
42
+
43
+ public editable function disconnect(callback: fn(payload: Payload) -> void) -> void:
44
+ var i: ptr_uint = 0
45
+ while i < this.count:
46
+ unsafe:
47
+ if this.slots[i] == callback:
48
+ # swap-remove with last
49
+ this.count = this.count - 1
50
+ if i < this.count:
51
+ this.slots[i] = this.slots[this.count]
52
+ return
53
+ i += 1
54
+
55
+
56
+ public function fire(payload: Payload) -> void:
57
+ var i: ptr_uint = 0
58
+ while i < this.count:
59
+ unsafe:
60
+ let cb = this.slots[i]
61
+ cb(payload)
62
+ i += 1
63
+
64
+
65
+ public function count() -> ptr_uint:
66
+ return this.count