;;;; Generic structs, end to end: type parameters and length parameters. ;;;; ;;;; A defstruct whose fields introduce $t is a template, and each set of ;;;; arguments it is given is a copy — an ordinary struct. A parameter is a ;;;; length when it stands in an array's length slot, and a type anywhere else; ;;;; the arguments are written in the order the fields first introduce them. ;;;; ;;;; Small is Odin's Small_Array: a fixed-capacity array with a count, and no ;;;; allocation anywhere. (defstruct Small [items [$n $t] count i32]) ;; A generic function over a generic struct binds both of its parameters from ;; the argument, and reads the length back as a value. (defn append! [s (Ptr (Small $n $t)) x $t] bool (if (< (.count s) n) (do (set (at (.items s) (.count s)) x) (set (.count s) (+ (.count s) 1)) true) false)) ;; One generic over the struct calling another at its own variables. (defn append-all! [s (Ptr (Small $n $t)) xs [$t]] () (dotimes [i (length xs)] (append! s (at xs i)))) (defn pop! [s (Ptr (Small $n $t))] (Option $t) (if (= (.count s) 0) None (do (set (.count s) (- (.count s) 1)) (Some (at (.items s) (.count s)))))) (defn capacity [s (Ptr (Small $n $t))] i32 n) (defn total [s (Ptr (Small $n $t))] $t {:where (numeric? $t)} (let [acc (the $t 0)] (dotimes [i (.count s)] (set acc (+ acc (at (.items s) i)))) acc)) ;; A type parameter alone, built positionally with the type read off the ;; fields, and returned under a variable. (defstruct Pair [a $t b $t]) (defn swapped [p (Pair $t)] (Pair $t) (Pair (.b p) (.a p))) ;; A copy that names itself through a pointer, and a literal field that ;; takes its width from the one beside it. (defstruct Node [v $t next (Option (Ptr (Node $t)))]) (defn sum-list [n (Ptr (Node i64))] i64 (let [at n acc (the i64 0)] (while true (set acc (+ acc (.v at))) (match (.next at) (Some p) (set at p) None (break))) acc)) ;; A template naming another at its own parameters. (defstruct Twice [x (Small $m $u) y (Small $m $u)]) ;; A copy as a map key, and a named function over one handed where a ;; function value is wanted. (defn pair-sum [p (Pair i32)] i32 (+ (.a p) (.b p))) (defn apply-to [f (Fn [(Pair i32)] i32) p (Pair i32)] i32 (f p)) ;; A length variable straight on an array parameter. (defn len-of [a [$k $e]] i32 k) (defconst cap 3) (defn main [] i32 (let [s (the (Small 4 i32) (zeroed)) f (the (Small cap f64) (zeroed))] (append! (addr s) 10) (append! (addr s) 20) (append! (addr s) 30) (println (total (addr s)) (.count s) (capacity (addr s))) (append! (addr f) 1.5) (append! (addr f) 2.5) (append! (addr f) 3.5) (println (append! (addr f) 4.5) (total (addr f)) (capacity (addr f))) (println (pop! (addr f)) (pop! (addr f)) (.count f)) (let [p (Pair 1 2) q (swapped p) r (swapped (Pair {.a 1.5 .b 2.5}))] (println (.a q) (.b q) (.a r) (.b r)) (println q (Pair 1 2.5))) (let [c (the (Node i64) {.v 3}) b (Node 2 (Some (addr c))) a (Node 1 (Some (addr b)))] (println (sum-list (addr a)))) (let [w (the (Twice 2 u8) (zeroed))] (append! (addr (.y w)) 7) (println (.count (.x w)) (.count (.y w)) (capacity (addr (.x w))))) (println (len-of [1 2 3]) (len-of [1.5 2.5])) (let [v (vec-new (Pair i32))] (push v (Pair 5 6)) (println (.b (at v 0))) (free v)) (let [t (the (Small 5 i64) (zeroed)) xs (the [3 i64] [1 2 3])] (append-all! (addr t) (slice xs)) (println (total (addr t)) (.count t))) (let [m (map-new (Pair i32) i32)] (put m (Pair 1 2) 12) (put m (Pair 3 4) 34) (println (get m (Pair 3 4)) (get m (Pair 2 1)) (apply-to pair-sum (Pair 7 8))) (free m)) 0))