diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/vec/test.mk | 1 | ||||
| -rw-r--r-- | tests/vec/vec.fwd | 153 |
2 files changed, 154 insertions, 0 deletions
diff --git a/tests/vec/test.mk b/tests/vec/test.mk new file mode 100644 index 0000000..4120ce5 --- /dev/null +++ b/tests/vec/test.mk @@ -0,0 +1 @@ +XPASS += vec diff --git a/tests/vec/vec.fwd b/tests/vec/vec.fwd new file mode 100644 index 0000000..b88d226 --- /dev/null +++ b/tests/vec/vec.fwd @@ -0,0 +1,153 @@ +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]; + + /* expand if we run out of space */ + if c > 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([c => n, s => s, nbuf => buf] vec); + } else { + /* if this were a generic vector we'd have to worry about + * destroying the elements, but since we're just dealing with + * integers this is fine */ + ok([c => n, s => s, buf => buf] vec); + } +} + +set_vec(vec v, i64 i, i64 e, (vec) ok) +{ + v => [n => n, s => s, buf => buf]; + /* oh wait, this is dumb, of course nbuf will never be null */ + buf + i => nbuf; + nil nbuf { + nil nbuf; + fwdfree(buf); + fwdpanic("set_vec, should never happen\n"); + } => dst; + + /* perform actual store */ + e => dst*; + + nil nbuf; + ok([n => n, s => s, buf => 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, e) => v; + ok(v); +} + +at_vec(vec v, u64 i, (vec > &i64) ok) +{ + v => [n => n, s => s, buf => buf]; + guard(i < n) => { + fwdfree(buf); + fwdpanic("at_vec, bounds error\n"); + } => ; + + buf + i => *i64 nbuf; + nil nbuf { + nil nbuf; + fwdfree(buf); + fwdpanic("at_vec, should never happen\n"); + } => &i64 bufr; + + nil nbuf; + 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 { + ok(); + } else { + err(); + } +} + +check_vec(i64 i, i64 n, vec v, (vec) ok) +{ + if i < n { + at_vec(v, i as u64) => v, elem; + + /* oh, this doesn't really work with the memory analysis, since + * I can destroy `v` but `elem` is still usable. I guess I could + * transform this such that `elem` is only alive within a + * closure? Not sure. */ + guard(elem* == i) => { + destroy_vec(v); + fwdpanic("check_vec, vec built wrong\n"); + } => ; + + 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); + + fwdprint_str("OK"); + fwdprint_nl(); +} |
