bv-sized-1.0.3: src/Data/BitVector/Sized/Signed.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeApplications #-}
{-|
Module : Data.BitVector.Sized.Signed
Copyright : (c) Galois Inc. 2018
License : BSD-3
Maintainer : benselfridge@galois.com
Stability : experimental
Portability : portable
This module defines a wrapper around the 'BV' type, 'SignedBV', with
instances not provided by 'BV'.
-}
module Data.BitVector.Sized.Signed
( SignedBV(..)
, mkSignedBV
) where
import Data.BitVector.Sized (BV, mkBV)
import qualified Data.BitVector.Sized.Internal as BV
import Data.BitVector.Sized.Panic (panic)
import Data.Parameterized.NatRepr
import Data.Bits (Bits(..), FiniteBits(..))
import Data.Ix
import GHC.Generics
import GHC.TypeLits
import Numeric.Natural
import System.Random
import System.Random.Stateful
-- | Signed bit vector.
newtype SignedBV w = SignedBV { asBV :: BV w }
deriving (Generic, Show, Read, Eq)
instance (KnownNat w, 1 <= w) => Ord (SignedBV w) where
SignedBV bv1 `compare` SignedBV bv2 =
if | bv1 == bv2 -> EQ
| BV.slt knownNat bv1 bv2 -> LT
| otherwise -> GT
-- | Convenience wrapper for 'BV.mkBV'.
mkSignedBV :: NatRepr w -> Integer -> SignedBV w
mkSignedBV w x = SignedBV (BV.mkBV w x)
liftUnary :: (BV w -> BV w)
-> SignedBV w
-> SignedBV w
liftUnary op (SignedBV bv) = SignedBV (op bv)
liftBinary :: (BV w -> BV w -> BV w)
-> SignedBV w
-> SignedBV w
-> SignedBV w
liftBinary op (SignedBV bv1) (SignedBV bv2) = SignedBV (op bv1 bv2)
liftBinaryInt :: (BV w -> Natural -> BV w)
-> SignedBV w
-> Int
-> SignedBV w
liftBinaryInt op (SignedBV bv) i = SignedBV (op bv (intToNatural i))
intToNatural :: Int -> Natural
intToNatural = fromIntegral
instance (KnownNat w, 1 <= w) => Bits (SignedBV w) where
(.&.) = liftBinary BV.and
(.|.) = liftBinary BV.or
xor = liftBinary BV.xor
complement = liftUnary (BV.complement knownNat)
shiftL = liftBinaryInt (BV.shl knownNat)
shiftR = liftBinaryInt (BV.ashr knownNat)
rotateL = liftBinaryInt (BV.rotateL knownNat)
rotateR = liftBinaryInt (BV.rotateR knownNat)
bitSize _ = widthVal (knownNat @w)
bitSizeMaybe _ = Just (widthVal (knownNat @w))
isSigned = const True
testBit (SignedBV bv) ix = BV.testBit' (intToNatural ix) bv
bit = SignedBV . BV.bit' knownNat . intToNatural
popCount (SignedBV bv) = fromInteger (BV.asUnsigned (BV.popCount bv))
instance (KnownNat w, 1 <= w) => FiniteBits (SignedBV w) where
finiteBitSize _ = widthVal (knownNat @w)
countLeadingZeros (SignedBV bv) = fromInteger $ BV.asUnsigned $ BV.clz knownNat bv
countTrailingZeros (SignedBV bv) = fromInteger $ BV.asUnsigned $ BV.ctz knownNat bv
instance (KnownNat w, 1 <= w) => Num (SignedBV w) where
(+) = liftBinary (BV.add knownNat)
(*) = liftBinary (BV.mul knownNat)
abs = liftUnary (BV.abs knownNat)
signum (SignedBV bv) = mkSignedBV knownNat $ signum $ BV.asSigned knownNat bv
fromInteger = SignedBV . mkBV knownNat
negate = liftUnary (BV.negate knownNat)
instance (KnownNat w, 1 <= w) => Enum (SignedBV w) where
toEnum = SignedBV . mkBV knownNat . checkInt
where checkInt i | lo <= toInteger i && toInteger i <= hi = toInteger i
| otherwise = panic "Data.BitVector.Sized.Signed"
["toEnum: bad argument"]
where lo = minSigned (knownNat @w)
hi = maxSigned (knownNat @w)
fromEnum (SignedBV bv) = fromInteger (BV.asSigned (knownNat @w) bv)
instance (KnownNat w, 1 <= w) => Ix (SignedBV w) where
range (SignedBV loBV, SignedBV hiBV) =
(SignedBV . mkBV knownNat) <$>
[BV.asSigned knownNat loBV .. BV.asSigned knownNat hiBV]
index (SignedBV loBV, SignedBV hiBV) (SignedBV ixBV) =
index ( BV.asSigned knownNat loBV
, BV.asSigned knownNat hiBV)
(BV.asSigned knownNat ixBV)
inRange (SignedBV loBV, SignedBV hiBV) (SignedBV ixBV) =
inRange ( BV.asSigned knownNat loBV
, BV.asSigned knownNat hiBV)
(BV.asSigned knownNat ixBV)
instance (KnownNat w, 1 <= w) => Bounded (SignedBV w) where
minBound = SignedBV (BV.minSigned knownNat)
maxBound = SignedBV (BV.maxSigned knownNat)
instance KnownNat w => Uniform (SignedBV w) where
uniformM g = SignedBV <$> BV.uniformM knownNat g
instance (KnownNat w, 1 <= w) => UniformRange (SignedBV w) where
uniformRM (SignedBV lo, SignedBV hi) g =
SignedBV <$> BV.sUniformRM knownNat (lo, hi) g
instance (KnownNat w, 1 <= w) => Random (SignedBV w)