;;;; 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 small-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 small-append-all [s (Ptr (Small $n $t)) xs [$t]] () (dotimes [i (length xs)] (small-append s (at xs i)))) (defn small-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 (is-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))] (small-append (addr s) 10) (small-append (addr s) 20) (small-append (addr s) 30) (println (total (addr s)) (.count s) (capacity (addr s))) (small-append (addr f) 1.5) (small-append (addr f) 2.5) (small-append (addr f) 3.5) (println (small-append (addr f) 4.5) (total (addr f)) (capacity (addr f))) (println (small-pop (addr f)) (small-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))] (small-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])] (small-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))