Carp/core/StaticArray.carp
2020-11-07 17:49:41 +00:00

222 lines
6.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(defmodule StaticArray
(doc map! "Maps a function over the static array `xs`, mutating it in place. The difference to Array.endo-map (which does the same thing internally) is that this function takes a ref (since you can never have static arrays as values) and that it returns ().")
(defn map! [xs f]
(for [i 0 (StaticArray.length xs)]
(StaticArray.aset! xs i (~f (StaticArray.unsafe-nth xs i)))))
(doc reverse! "Reverse array in place.")
(defn reverse! [a]
(let-do [i 0
j (Int.dec (length a))]
(while (Int.< i j)
(let-do [tmp @(unsafe-nth a i)]
(aset! a i @(unsafe-nth a j))
(set! i (Int.inc i))
(aset! a j tmp)
(set! j (Int.dec j))))))
(defndynamic foreach-internal [var xs expr]
(let [xsym (gensym-with 'xs)
len (gensym-with 'len)
i (gensym-with 'i)]
(list 'let [xsym xs
len (list 'StaticArray.length xsym)]
(list 'for [i 0 len]
(list 'let [var (list 'StaticArray.unsafe-nth xsym i)]
expr)))))
(defmacro foreach [binding expr]
(StaticArray.foreach-internal (car binding) (cadr binding) expr))
(defn reduce [f x xs]
(let [total x]
(do
(for [i 0 (StaticArray.length xs)]
(set! total (~f total (StaticArray.unsafe-nth xs i))))
total)))
(doc = "compares two static arrays.")
(defn = [a b]
(if (/= (StaticArray.length a) (StaticArray.length b))
false
(let-do [eq true]
(for [i 0 (StaticArray.length a)]
(when (/= (StaticArray.unsafe-nth a i) (StaticArray.unsafe-nth b i))
(do
(set! eq false)
(break))))
eq)))
(implements = StaticArray.=)
(doc empty? "checks whether the array `a` is empty.")
(defn empty? [a]
(= (StaticArray.length a) 0))
(doc any? "checks whether any of the elements in `a` match the function `f`.")
(defn any? [f a]
(let-do [res false]
(for [i 0 (length a)]
(when (~f (unsafe-nth a i))
(do
(set! res true)
(break))))
res))
(doc all? "checks whether all of the elements in `a` match the function `f`.")
(defn all? [f a]
(let-do [res true]
(for [i 0 (length a)]
(when (not (~f (unsafe-nth a i)))
(do
(set! res false)
(break))))
res))
(doc find "finds an element in `a` that matches the function `f` and wraps it in a `Just`.
If it doesnt find an element, `Nothing` will be returned.")
(defn find [f a]
(let-do [res (Maybe.Nothing)]
(for [i 0 (length a)]
(when (~f (unsafe-nth a i))
(do
(set! res (Maybe.Just @(unsafe-nth a i)))
(break))))
res))
(doc find-index "finds the index of the first element in `a` that matches the function `f` and wraps it in a `Just`.
If it doesnt find an index, `Nothing` will be returned.")
(defn find-index [f a]
(let-do [ret (Maybe.Nothing)]
(for [i 0 (length a)]
(when (~f (unsafe-nth a i))
(do
(set! ret (Maybe.Just i))
(break))))
ret))
(doc unsafe-first "takes the first element of an array.
Generates a runtime error if the array is empty.")
(defn unsafe-first [a]
@(unsafe-nth a 0))
(doc first "takes the first element of an array and returns a `Just`.
Returns `Nothing` if the array is empty.")
(defn first [a]
(if (empty? a)
(Maybe.Nothing)
(Maybe.Just @(unsafe-nth a 0))))
(doc unsafe-last "takes the last element of an array.
Generates a runtime error if the array is empty.")
(defn unsafe-last [a]
@(unsafe-nth a (Int.dec (length a))))
(doc last "takes the last element of an array and returns a `Just`.
Returns `Nothing` if the array is empty.")
(defn last [a]
(if (empty? a)
(Maybe.Nothing)
(Maybe.Just @(unsafe-nth a (Int.dec (length a))))))
(doc maximum "gets the maximum in an array (elements must support `<`) and wraps it in a `Just`.
If the array is empty, it returns `Nothing`.")
(defn maximum [xs]
(if (empty? xs)
(Maybe.Nothing)
(let-do [result (unsafe-nth xs 0)
n (length xs)]
(for [i 1 n]
(let [x (unsafe-nth xs i)]
(when (< result x)
(set! result x))))
(Maybe.Just @result))))
(doc minimum "gets the minimum in an array (elements must support `>`) and wraps it in a `Just`.
If the array is empty, returns `Nothing`")
(defn minimum [xs]
(if (empty? xs)
(Maybe.Nothing)
(let-do [result (unsafe-nth xs 0)
n (length xs)]
(for [i 1 n]
(let [x (unsafe-nth xs i)]
(when (> result x)
(set! result x))))
(Maybe.Just @result))))
(doc sum "sums an array (elements must support `+` and `zero`).")
(defn sum [xs]
(reduce &(fn [x y] (+ x @y)) (zero) xs))
(doc index-of "gets the index of element `e` in an array and wraps it on a `Just`.
If the element is not found, returns `Nothing`")
(defn index-of [a e]
(let-do [idx (Maybe.Nothing)]
(for [i 0 (length a)]
(when (= (unsafe-nth a i) e)
(do
(set! idx (Maybe.Just i))
(break))))
idx))
(doc element-count "counts the occurrences of element `e` in an array.")
(defn element-count [a e]
(let-do [c 0]
(for [i 0 (length a)]
(when (= e (unsafe-nth a i)) (set! c (Int.inc c))))
c))
(doc predicate-count "counts the number of elements satisfying the predicate function `pred` in an array.")
(defn predicate-count [a pred]
(let-do [c 0]
(for [i 0 (length a)]
(when (~pred (unsafe-nth a i))
(set! c (Int.inc c))))
c))
(doc aupdate! "transmutes (i.e. updates) the element at index `i` of an array `a` using the function `f` in place.")
(defn aupdate! [a i f]
(aset! a i (~f (unsafe-nth a i))))
(doc swap! "swaps the indices `i` and `j` of an array `a` in place.")
(defn swap! [a i j]
(let-do [x @(unsafe-nth a i)
y @(unsafe-nth a j)]
(aset! a i y)
(aset! a j x)))
(doc nth "gets a reference to the `n`th element from an array `arr` wrapped on a `Maybe`.
If the `index` is out of bounds, return `Maybe.Nothing`")
(defn nth [xs index]
(if (and (>= index 0) (< index (length xs)))
(Maybe.Just @(unsafe-nth xs index)) ; the copy will go away with lifetimes
(Maybe.Nothing)))
(doc contains? "checks wether an element exists in the array.")
(defn contains? [arr el]
(let-do [result false]
(for [i 0 (length arr)]
(when (= el (unsafe-nth arr i))
(do
(set! result true)
(break))))
result))
(doc unsafe-raw "returns an array a as a raw pointer—useful for interacting with C.")
(deftemplate unsafe-raw (Fn [(Ref (StaticArray t))] (Ptr t))
"$t* $NAME(Array *a)"
"$DECL { return a->data; }"))