{-# 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
( 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
newtype SignedBV w = SignedBV (BV w)
deriving (Generic, Show, Read, Eq)
mkSignedBV :: NatRepr w -> Integer -> SignedBV w
mkSignedBV w x = SignedBV (BV.mkBV w x)
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
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)