86 lines
2.3 KiB
Plaintext

; A fixed-size ring buffer of samples, generic over the element type, with
; the statistics a sensor log wants: a median, the distinct values, and a
; checksum over the raw bytes.
struct Ring
items: [$n $t]
head: i32
count: i32
struct Reading
sensor: u8
value: i32
fn push-ring!(r: Ptr(Ring($n, $t)), x: $t) -> ()
r.items[r.head] = x
r.head = (r.head + 1) % n
if r.count < n
r.count += 1
; The oldest sample first.
fn nth-oldest(r: Ptr(Ring($n, $t)), i: i32) -> $t
let start = if r.count < n then 0 else r.head
r.items[(start + i) % n]
fn copy-out(r: Ptr(Ring($n, $t))) -> Vec($t)
let v = vec-new(t)
for i in range(r.count)
push(v, nth-oldest(r, i))
v
fn median(xs: [$t]) -> Option($t) where ordered?($t), equal?($t)
if length(xs) == 0
return None
sort(xs)
Some(xs[length(xs) / 2])
fn distinct(xs: [const $t]) -> Vec($t) where equal?($t), hashable?($t)
let seen = map-new(t, bool)
defer free(seen)
let out = vec-new(t)
for i in range(length(xs))
if not has-key?(seen, xs[i])
put(seen, xs[i], true)
push(out, xs[i])
out
; FNV-1a over the bytes of any array of plain values.
fn checksum(p: Ptr(u8), size: i64) -> u32
let bytes = slice-from(p, size)
let h: u32 = 2166136261
for i in range(length(bytes))
h = bit-xor(h, u32(bytes[i]))
h = h * 16777619
h
fn main() -> i32
let r: Ring(5, i32) = zeroed()
let samples = [7 3 9 3 12 5 3 8]
for :fill i in range(length(samples))
if samples[i] > 10
continue :fill
push-ring!(addr(r), samples[i])
let kept = copy-out(addr(r))
defer free(kept)
println("kept", slice(kept))
match median(slice(kept))
Some(m) -> println("median", m)
None -> println("no samples")
let empty: [0 i32] = zeroed()
println("median of none", or-else(median(slice(empty)), -1))
let d = distinct(slice(samples))
println("distinct", slice(d))
free(d)
let big = filter(slice(samples), fn(x) = x >= 7)
println("seven and up", slice(big), "sum", reduce(slice(big), 0, fn(a, b) = a + b))
free(big)
let rs = [Reading{.sensor 2, .value 40} Reading{.sensor 1, .value 15}
Reading{.sensor 3, .value 22}]
sort-by(slice(rs), fn(a, b) = a.value < b.value)
for i in range(length(rs))
println("sensor", rs[i].sensor, rs[i].value)
let raw: [4 u32] = [1 2 3 4]
let p = Ptr(u8)(addr(raw[0]))
println("checksum", checksum(p, 16))
0