nx_iterator.nx
buildroot/runtime/nx_iterator.nx
about
nx_iterator.nx -- composable iteration; kills the nested-loops bug class.
User cardinal 2026-05-15: "how many loops within loops type bullshit
do we create that then caused memory leaks and infinite bloat etc,
isnt it better just to build the system so its bulletproof there
where a loop can call another loop like a function but with better
structure i feel like javascript c etc have all created a shit
paradigm not a usability paradagim."
THE STRUCTURAL FIX: first-class iterators. A pipeline of N
transformations expresses as ONE while loop at the consumption end
instead of N nested loops. Zero raw nesting; zero per-iteration
allocations; clear ownership.
Example transformation -- 5 stages, 1 loop:
let it: *Iterator = nx_iter_range(0, 100)
it = nx_iter_filter(it, NX_FILTER_EVEN, 0)
it = nx_iter_map(it, NX_MAP_SQUARE, 0)
it = nx_iter_take(it, 5)
let v: *nx_int = (sys_mmap(NX_SIZEOF_NX_INT)) as *nx_int
while nx_iter_next(it, v) == 1 {
// v[0] = next squared even number, up to 5 of them
}
Same logic in nested-loop style would be 4 deep with per-level
state, easy to leak. Iterator style: linear, audit-able, the
substrate's Captain Moroni doctrine applied to iteration.
NO-CLOSURE-NEEDED DESIGN: filter / map use the same sealed-enum
predicate/op kinds as nx_array_ops.nx (NX_FILTER_* and NX_MAP_*).
Substrate dispatches internally. ~80% coverage; the remaining
20% custom predicates wait for closure support (queued nxc2 work).
CONSUMERS use NX_REDUCE_* op kinds from nx_array_ops.nx (SUM /
PRODUCT / MIN / MAX / COUNT / AND / OR / XOR) for fold semantics.
MEMORY: each iterator is a fixed-size struct (8 nx_int fields +
1 array pointer + 2 inner pointers = ~88 bytes). Per-pipeline
allocation is O(stages) and bounded; no per-iteration allocations.
dependencies 3 imports · 1 importers
imports: nx_syscalls.nxnx_tier.nxnx_array_ops.nx
imported by: nx_iterator_test.nx
structs
| 86 | struct Iterator |
consts
| 57 | const NX_MAGIC_1024: i64 = 1024 |
| 61 | const NX_ITER_KIND_RANGE: nx_int = 0 |
| 62 | const NX_ITER_KIND_ARRAY: nx_int = 1 |
| 63 | const NX_ITER_KIND_FILTERED: nx_int = 2 |
| 64 | const NX_ITER_KIND_MAPPED: nx_int = 3 |
| 65 | const NX_ITER_KIND_CHAINED: nx_int = 4 |
| 66 | const NX_ITER_KIND_TAKE: nx_int = 5 |
| 67 | const NX_ITER_KIND_SKIP: nx_int = 6 |
| 68 | const NX_ITER_N_KINDS: nx_int = 7 |
functions
| 99 | func _iter_alloc() -> *Iterator called by 7: nx_iter_rangenx_iter_arraynx_iter_filternx_iter_mapnx_iter_chainnx_iter_take+1 calls 1: sys_mmap |
| 107 | func nx_iter_range(lo: nx_int, hi: nx_int) -> *Iterator |
| 115 | func nx_iter_array(arr: *nx_int, n: nx_int) -> *Iterator |
| 126 | func nx_iter_filter(source: *Iterator, pred: nx_int, param: nx_int) -> *Iterator |
| 135 | func nx_iter_map(source: *Iterator, op: nx_int, param: nx_int) -> *Iterator |
| 144 | func nx_iter_chain(a: *Iterator, b: *Iterator) -> *Iterator |
| 153 | func nx_iter_take(source: *Iterator, n: nx_int) -> *Iterator |
| 161 | func nx_iter_skip(source: *Iterator, n: nx_int) -> *Iterator |
| 175 | func _iter_filter_match(v: nx_int, pred: nx_int, param: nx_int) -> nx_int called by 1: nx_iter_next |
| 196 | func _iter_map_apply(v: nx_int, op: nx_int, param: nx_int) -> nx_int called by 1: nx_iter_next |
| 230 | func nx_iter_next(it: *Iterator, out: *nx_int) -> nx_int |
| 302 | func nx_iter_count(it: *Iterator) -> nx_int |
| 312 | func nx_iter_reduce(it: *Iterator, op: nx_int) -> nx_int |
| 344 | func nx_iter_sum(it: *Iterator) -> nx_int |
| 348 | func nx_iter_min(it: *Iterator) -> nx_int |
| 352 | func nx_iter_max(it: *Iterator) -> nx_int |
| 358 | func nx_iter_collect(it: *Iterator, out: *nx_int, max_out: nx_int) -> nx_int |
| 371 | func nx_iter_kind_is_valid(k: nx_int) -> nx_int called by 1: main |