import "../mod/libfwdio.so" import "../mod/libfwdmem.so" import "../mod/libfwdutil.so" vec { u64 n; u64 s; *i64 buf; } init_vec(u64 n, (vec) ok) { ok([n => n, 0 as u64 => s, * => buf] vec); } next_s_vec(u64 s, (u64) ok) { if s == 0 as u64 { ok(1 as u64); } else { ok(2 as u64 * s); } } reserve_vec(vec v, u64 c, (vec) ok) { v => [n => n, s => s, buf => buf]; n + c => nn; /* expand if we run out of space */ if nn > s { next_s_vec(s) => s; /* note that fwdrealloc creates a new closure, meaning that it * takes ownership of v.buf, so we can't back out and do a * single ok(v) at the end of the function */ fwdrealloc(buf, s * sizeof(i64)) => nbuf; ok([nn => n, s => s, nbuf => buf] vec); } else { ok([nn => n, s => s, buf => buf] vec); } } set_vec(vec v, i64 i, i64 e, (vec) ok) { v => [n => n, s => s, buf => buf]; buf + (n - 1 as u64) => nbuf; nil nbuf {fwdpanic("should never happen");} => dst; e => dst*; ok([n => n, s => s, nbuf => buf] vec); } n_vec(vec v, (vec, u64) ok) { v => [n => n, s => s, buf => buf]; ok([n => n, s => s, buf => buf] vec, n); } append_vec(vec v, i64 e, (vec) ok) { n_vec(v) => v, n; reserve_vec(v, n + 1 as u64) => v; set_vec(v, n as i64 - 1, e) => v; ok(v); } at_vec(vec v, u64 i, (vec, &i64) ok) { v => [n => n, s => s, buf => buf]; if i >= n {fwdpanic("bounds error");} fwdptradd(buf, (i * sizeof(i64)) as i64) => *i64 buf; nil buf {fwdpanic("should never happen");} => &i64 bufr; ok([n => n, s => s, buf => buf] vec, bufr); } destroy_vec(vec v) { v => [n => n, s => s, buf => buf]; fwdfree(buf); nil n; nil s; } populate_vec(i64 i, i64 n, vec v, (vec) ok) { if i < n { append_vec(v, i) => vec v; populate_vec(i + 1, n, v, ok); } else { ok(v); } } guard(bool c, () err | () ok) { if c { err(); } else { ok(); } } check_vec(i64 i, i64 n, vec v, (vec) ok) { if i < n { at_vec(v, i as u64) => v, elem; guard(elem* != i) => { destroy_vec(v); fwdpanic("vec built wrong"); } => ; check_vec(i + 1, n, v, ok); } else { ok(v); } } main() { init_vec(0 as u64) => vec v; populate_vec(0, 1000000, v) => vec v; check_vec(0, 1000000, v) => vec v; destroy_vec(v); }