flan/test/programs/generic-struct.flan

112 lines
3.9 KiB
Plaintext

;;;; 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))