package OInt(OInt, toOInt, fromOInt, select) where import Vector --@ \subsubsection{OInt} --@ --@ \index{OInt@\te{OInt} (type)|textbf} --@ The {\mbox{\te{OInt n}}} type is a type that can store --@ a number in the range \qbs{0..n-1}. --@ The representation of a \qbs{OInt n} takes up $n$ bits, where --@ exactly one bit is a set to one, and the others are zero, i.e., it is --@ a ``one-hot'' decoded version of the number. --@ The reason to use a \te{OInt} number is that the \te{select} --@ operation is more efficient than for an ordinary number; --@ the code generated for select takes advantage of the fact that --@ only one of the bits may be set at a time. --@ --@ \begin{libverbatim} --@ typedef ... OInt #(type n) ... ; --@ \end{libverbatim} data OInt n = O (Vector n Bool) deriving (Bits) --@ Numeric literals can be used as usual (indicating which --@ bit should be set). --@ \begin{libverbatim} --@ instance Literal #(OInt#(n)); --@ \end{libverbatim} instance Literal (OInt n) where fromInteger i = let result :: OInt n result = O (map ((==) i) genList) in if (isStaticIndex i) then if (inLiteralRange result i) then result else error (integerToString i + " is not a legal OInt#(" + integerToString (valueOf n) + ").") else -- don't check non-static integers result inLiteralRange _ i = i >= 0 && i < (valueOf n) --@ Values can be compared for equality. --@ \begin{libverbatim} --@ instance Eq #(OInt#(n)); --@ \end{libverbatim} instance Eq (OInt n) where (==) (O xs) (O ys) = or (zipWith (&&) xs ys) (/=) (O xs) (O ys) = not (or (zipWith (&&) xs ys)) instance (Log n k) => Ord (OInt n) where (<) x y = fromOInt x < fromOInt y (<=) x y = fromOInt x <= fromOInt y (>) x y = fromOInt x > fromOInt y (>=) x y = fromOInt x >= fromOInt y instance (Log n k) => PrimIndex (OInt n) k where isStaticIndex = compose isStaticIndex pack toStaticIndex = compose toStaticIndex fromOInt toDynamicIndex = fromOInt --@ There are upper and lower bounds. --@ \begin{libverbatim} --@ instance Bounded #(OInt#(n)); --@ \end{libverbatim} instance Bounded (OInt n) where minBound = fromInteger 0 maxBound = fromInteger (valueOf n - 1) instance PrimSelectable (OInt n) Bool where primSelectFn pos (O xs) = primSelectFn pos xs --@ An ordinary number can be converted to an \te{OInt}. --@ An out-of-range number gives an unspecified result. --@ \begin{libverbatim} --@ function OInt#(n) toOInt(Bit#(k) k) --@ provisos( Log#(n,k)) ; --@ \end{libverbatim} toOInt :: (Log n k ) => Bit k -> OInt n toOInt k = O (map (\ i -> fromInteger i == k) genList) --@ An \te{OInt} can be converted to an ordinary number. --@ \begin{libverbatim} --@ function Bit#(k) fromOInt(OInt#(n) o) --@ provisos( Log#(n,k)) ; --@ \end{libverbatim} fromOInt :: (Log n k ) => OInt n -> Bit k fromOInt o = select (map fromInteger genList) o --@ An \te{OInt} can be used to select an element from a --@ Vector in an efficient way. --@ \begin{libverbatim} --@ function a select(Vector#(n, a) xs, OInt#(n) o) --@ provisos (Bits#(a, sa)); --@ \end{libverbatim} select :: (Bits a sa) => Vector n a -> OInt n -> a select xs (O bs) = let f x b = let vb :: Vector sa Bool vb = unpack (pack x) in map ((&&) b) vb in unpack (pack (map or (transpose (zipWith f xs bs)))) or :: Vector n Bool -> Bool or = foldr (||) False