package UIntRange(UIntRange, incr, decr) where --@ \subsubsection{UIntRange} --@ --@ \index{UIntRange@\te{UIntRange} (type)|textbf} --@ The type {\mbox{\te{UIntRange lo hi}}} represents an unsigned integer --@ using the number of bits needed to store \qbs{hi}. --@ The values of the type are in the range \qbs{lo..hi}. --@ --@ The advantage of using \te{UIntRange} over \te{UInt} --@ is that the compiler can take advantage of the range information --@ when compiling the program. It also makes the code more self-documenting --@ and catches more type errors. --@ --@ {\bf NOTE}, using \te{unpack} it is possible to make a value that is --@ not within the specified range. Doing so will result in unspecified --@ behaviour. --@ --@ \BBS --@ data UIntRange lo hi = {\rm{\emph{$\cdots$ abstract $\cdots$}}} --@ \EBS data (UIntRange :: # -> # -> *) lo hi = U (Bit (TLog (TAdd hi 1))) deriving (Eq, Ord) primitive primRange :: Bit n -> Bit n -> Bit n -> Bit n --@ \begin{libverbatim} --@ instance Bits #(UIntRange#(lo, hi), TLog#(TAdd#(hi, 1))); --@ \end{libverbatim} instance Bits (UIntRange lo hi) (TLog (TAdd hi 1)) where pack (U x) = x -- primRange (fromInteger (valueOf lo)) (fromInteger (valueOf hi)) x unpack x = U x -- (primRange (fromInteger (valueOf lo)) (fromInteger (valueOf hi)) x) --@ \lineup --@ \begin{libverbatim} --@ instance Literal #(UIntRange#(lo, hi)); --@ \end{libverbatim} instance Literal (UIntRange lo hi) where fromInteger i = if i < valueOf lo || i > valueOf hi then error ("UIntRange: literal out of range: " +++ integerToString i) else U (fromInteger i) inLiteralRange _ i = i >= valueOf lo && i <= valueOf hi --@ \lineup --@ \begin{libverbatim} --@ instance Bounded #(UIntRange#(lo, hi)); --@ \end{libverbatim} instance Bounded (UIntRange lo hi) where minBound = fromInteger (valueOf lo) maxBound = fromInteger (valueOf hi) -- Arith is easy to define once the semantic has been decided --@ Increment a value. This operation wraps around so --@ incrementing \qbs{hi} gives the value \qbs{lo}. --@ \begin{libverbatim} --@ incr :: UIntRange#(lo, hi) -> UIntRange#(lo, hi); --@ \end{libverbatim} incr :: UIntRange lo hi -> UIntRange lo hi incr (U x) = let bhi = fromInteger (valueOf hi) `asTypeOf` x blo = fromInteger (valueOf lo) `asTypeOf` x in if bhi+1 /= blo && x == bhi then U blo else U (x+1) --@ Decrement a value. This operation wraps around so --@ decrementing \qbs{lo} gives the value \qbs{hi}. --@ \begin{libverbatim} --@ decr :: UIntRange#(lo, hi) -> UIntRange#(lo, hi); --@ \end{libverbatim} decr :: UIntRange lo hi -> UIntRange lo hi decr (U x) = let bhi = fromInteger (valueOf hi) `asTypeOf` x blo = fromInteger (valueOf lo) `asTypeOf` x in if blo-1 /= bhi && x == blo then U bhi else U (x-1)