predicate-typed-0.7.4.4: src/Predicate/Data/Bits.hs
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE NoStarIsType #-}
{-# LANGUAGE EmptyDataDeriving #-}
{-# LANGUAGE DerivingStrategies #-}
-- | promoted bit manipulation functions
module Predicate.Data.Bits (
type (.&.)
, type (.|.)
, type (.^.)
, BitShift
, BitShiftL
, BitShiftR
, BitRotate
, BitRotateL
, BitRotateR
, BitSet
, BitComplement
, BitClear
, PopCount
, TestBit
, Bit
, ZeroBits
) where
import Predicate.Core
import Predicate.Util
import Data.Proxy (Proxy(Proxy))
import qualified Data.Bits as Bits
import Data.Bits (Bits(..))
-- $setup
-- >>> :set -XDataKinds
-- >>> :set -XTypeApplications
-- >>> :set -XTypeOperators
-- >>> :set -XOverloadedStrings
-- >>> import Predicate.Prelude
-- | bitwise @and@ similar to 'Data.Bits..&.'
--
-- >>> pz @(344 .&. 123) ()
-- Val 88
--
data p .&. q deriving Show
infixl 7 .&.
instance ( P p a
, P q a
, Show (PP p a)
, PP p a ~ PP q a
, Bits (PP p a)
) => P (p .&. q) a where
type PP (p .&. q) a = PP p a
eval _ opts a = do
let msg0 = "(.&.)"
lr <- runPQ NoInline msg0 (Proxy @p) (Proxy @q) opts a []
pure $ case lr of
Left e -> e
Right (p,q,pp,qq) ->
let hhs = [hh pp, hh qq]
d = p Bits..&. q
in mkNode opts (Val d) (showL opts p <> " .&. " <> showL opts q <> " = " <> showL opts d) hhs
-- | bitwise @or@ similar to 'Data.Bits..|.'
--
-- >>> pz @(344 .|. 123) ()
-- Val 379
--
-- >>> pz @(Fst .|. Snd) (124,33)
-- Val 125
--
data p .|. q deriving Show
infixl 5 .|.
instance ( P p a
, P q a
, Show (PP p a)
, PP p a ~ PP q a
, Bits (PP p a)
) => P (p .|. q) a where
type PP (p .|. q) a = PP p a
eval _ opts a = do
let msg0 = "(.|.)"
lr <- runPQ NoInline msg0 (Proxy @p) (Proxy @q) opts a []
pure $ case lr of
Left e -> e
Right (p,q,pp,qq) ->
let hhs = [hh pp, hh qq]
d = p Bits..|. q
in mkNode opts (Val d) (showL opts p <> " .|. " <> showL opts q <> " = " <> showL opts d) hhs
-- | bitwise @xor@ similar to 'Data.Bits.xor'
--
-- >>> pz @(344 .^. 123) ()
-- Val 291
--
data p .^. q deriving Show
infixl 5 .^.
instance ( P p a
, P q a
, Show (PP p a)
, PP p a ~ PP q a
, Bits (PP p a)
) => P (p .^. q) a where
type PP (p .^. q) a = PP p a
eval _ opts a = do
let msg0 = "(.^.)"
lr <- runPQ NoInline msg0 (Proxy @p) (Proxy @q) opts a []
pure $ case lr of
Left e -> e
Right (p,q,pp,qq) ->
let hhs = [hh pp, hh qq]
d = p `Bits.xor` q
in mkNode opts (Val d) (showL opts p <> " .^. " <> showL opts q <> " = " <> showL opts d) hhs
data BitFunction =
BFShift
| BFShiftL
| BFShiftR
| BFRotate
| BFRotateL
| BFRotateR
| BFSet
| BFClear
| BFComplement
deriving (Show,Eq)
class BitFunctionC (fn :: BitFunction) where
bitFunction :: Bits a => (String, a -> Int -> a)
instance BitFunctionC 'BFShift where
bitFunction = ("shift", Bits.shift)
instance BitFunctionC 'BFShiftL where
bitFunction = ("shiftL", Bits.shiftL)
instance BitFunctionC 'BFShiftR where
bitFunction = ("shiftR", Bits.shiftR)
instance BitFunctionC 'BFRotate where
bitFunction = ("rotate", Bits.rotate)
instance BitFunctionC 'BFRotateL where
bitFunction = ("rotateL", Bits.rotateL)
instance BitFunctionC 'BFRotateR where
bitFunction = ("rotateR", Bits.rotateR)
instance BitFunctionC 'BFSet where
bitFunction = ("setBit", Bits.setBit)
instance BitFunctionC 'BFClear where
bitFunction = ("clearBit", Bits.clearBit)
instance BitFunctionC 'BFComplement where
bitFunction = ("complementBit", Bits.complementBit)
-- flips the function where p is the integral
data BitImpl (fn :: BitFunction) p q deriving Show
instance ( P p a
, P q a
, Show (PP q a)
, Bits (PP q a)
, Integral (PP p a)
, BitFunctionC fn
) => P (BitImpl fn p q) a where
type PP (BitImpl fn p q) a = PP q a
eval _ opts a = do
let msg0 = ss
(ss,fn) = bitFunction @fn
lr <- runPQ NoInline msg0 (Proxy @p) (Proxy @q) opts a []
pure $ case lr of
Left e -> e
Right (fromIntegral -> p,q,pp,qq) ->
let hhs = [hh pp, hh qq]
d = fn q p
in mkNode opts (Val d) (ss <> " " <> showL opts p <> " " <> showL opts q <> " = " <> showL opts d) hhs
-- | shift by @p@ using @q@: similar to flipped version of 'Data.Bits.shift'
--
-- >>> pz @(BitShift 1 7) ()
-- Val 14
--
-- >>> pz @(BitShift 1 Id) 123
-- Val 246
--
data BitShift p q deriving Show
type BitShiftT p q = BitImpl 'BFShift p q
instance P (BitShiftT p q) x => P (BitShift p q) x where
type PP (BitShift p q) x = PP (BitShiftT p q) x
eval _ = eval (Proxy @(BitShiftT p q))
-- | shift left by @p@ using @q@: similar to flipped version of 'Data.Bits.shiftL'
--
-- >>> pz @(BitShiftL 1 Id) 123
-- Val 246
--
data BitShiftL p q deriving Show
type BitShiftLT p q = BitImpl 'BFShiftL p q
instance P (BitShiftLT p q) x => P (BitShiftL p q) x where
type PP (BitShiftL p q) x = PP (BitShiftLT p q) x
eval _ = eval (Proxy @(BitShiftLT p q))
-- | shift right by @p@ using @q@: similar to flipped version of 'Data.Bits.shiftR'
--
-- >>> pz @(BitShiftR 1 Id) 123
-- Val 61
--
data BitShiftR p q deriving Show
type BitShiftRT p q = BitImpl 'BFShiftR p q
instance P (BitShiftRT p q) x => P (BitShiftR p q) x where
type PP (BitShiftR p q) x = PP (BitShiftRT p q) x
eval _ = eval (Proxy @(BitShiftRT p q))
-- | rotate by @p@ using @q@: similar to flipped version of 'Data.Bits.rotate'
--
-- >>> pz @(BitRotate 2 Id) 7
-- Val 28
--
data BitRotate p q deriving Show
type BitRotateT p q = BitImpl 'BFRotate p q
instance P (BitRotateT p q) x => P (BitRotate p q) x where
type PP (BitRotate p q) x = PP (BitRotateT p q) x
eval _ = eval (Proxy @(BitRotateT p q))
-- | rotate left by @p@ using @q@: similar to flipped version of 'Data.Bits.rotateL'
--
-- >>> pz @(BitRotateL 2 Id) 7
-- Val 28
--
data BitRotateL p q deriving Show
type BitRotateLT p q = BitImpl 'BFRotateL p q
instance P (BitRotateLT p q) x => P (BitRotateL p q) x where
type PP (BitRotateL p q) x = PP (BitRotateLT p q) x
eval _ = eval (Proxy @(BitRotateLT p q))
-- | rotate right by @p@ using @q@: similar to flipped version of 'Data.Bits.rotateR'
--
-- >>> pz @(BitRotateR 2 Id) 7
-- Val 1
--
data BitRotateR p q deriving Show
type BitRotateRT p q = BitImpl 'BFRotateR p q
instance P (BitRotateRT p q) x => P (BitRotateR p q) x where
type PP (BitRotateR p q) x = PP (BitRotateRT p q) x
eval _ = eval (Proxy @(BitRotateRT p q))
-- | set the bit at @p@ using @q@: similar to flipped version of 'Data.Bits.setBit'
--
-- >>> pz @(BitSet 0 Id) 8
-- Val 9
--
data BitSet p q deriving Show
type BitSetT p q = BitImpl 'BFSet p q
instance P (BitSetT p q) x => P (BitSet p q) x where
type PP (BitSet p q) x = PP (BitSetT p q) x
eval _ = eval (Proxy @(BitSetT p q))
-- | clear the bit at @p@ using @q@: similar to flipped version of 'Data.Bits.clearBit'
--
-- >>> pz @(BitClear 2 Id) 7
-- Val 3
--
data BitClear p q deriving Show
type BitClearT p q = BitImpl 'BFClear p q
instance P (BitClearT p q) x => P (BitClear p q) x where
type PP (BitClear p q) x = PP (BitClearT p q) x
eval _ = eval (Proxy @(BitClearT p q))
-- | complement the bit at @p@ using @q@: similar to flipped version of 'Data.Bits.complementBit'
--
-- >>> pz @(BitComplement 1 Id) 7
-- Val 5
--
data BitComplement p q deriving Show
type BitComplementT p q = BitImpl 'BFComplement p q
instance P (BitComplementT p q) x => P (BitComplement p q) x where
type PP (BitComplement p q) x = PP (BitComplementT p q) x
eval _ = eval (Proxy @(BitComplementT p q))
-- | test the bit at @p@ using @q@: similar to flipped version of 'Data.Bits.testBit'
--
-- >>> pz @(TestBit 2 Id) 7
-- Val True
--
-- >>> pz @(TestBit 2 Id) 8
-- Val False
--
data TestBit p q deriving Show
instance ( P p a
, P q a
, Show (PP q a)
, Bits (PP q a)
, Integral (PP p a)
) => P (TestBit p q) a where
type PP (TestBit p q) a = Bool
eval _ opts a = do
let msg0 = "TestBit"
lr <- runPQ NoInline msg0 (Proxy @p) (Proxy @q) opts a []
pure $ case lr of
Left e -> e
Right (fromIntegral -> p,q,pp,qq) ->
let hhs = [hh pp, hh qq]
d = Bits.testBit q p
in mkNodeB opts d (msg0 <> " " <> showL opts p <> " " <> showL opts q <> " = " <> showL opts d) hhs
-- | count number of bits at @p@: similar to 'Data.Bits.popCount'
--
-- >>> pz @(PopCount Id) 7
-- Val 3
--
-- >>> pz @(PopCount Id) 8
-- Val 1
--
-- >>> pz @(PopCount Id) (-7)
-- Val (-3)
--
data PopCount p deriving Show
instance ( P p a
, Show (PP p a)
, Bits (PP p a)
) => P (PopCount p) a where
type PP (PopCount p) a = Int
eval _ opts a = do
let msg0 = "PopCount"
pp <- eval (Proxy @p) opts a
pure $ case getValueLR NoInline opts msg0 pp [] of
Left e -> e
Right p ->
let d = Bits.popCount p
in mkNode opts (Val d) (msg0 <> " " <> showL opts p <> " = " <> showL opts d) [hh pp]
-- | create a 'Data.Bits.Bits' for type @t with the bit at @p@ and all the others set to zero: similar to 'Data.Bits.bit'
--
-- >>> pz @(Bit Int Id) 0
-- Val 1
--
-- >>> pz @(Bit Int Id) 3
-- Val 8
--
data Bit t p deriving Show
instance ( P p a
, Show t
, Bits t
, Integral (PP p a)
) => P (Bit t p) a where
type PP (Bit t p) a = t
eval _ opts a = do
let msg0 = "Bit"
pp <- eval (Proxy @p) opts a
pure $ case getValueLR NoInline opts msg0 pp [] of
Left e -> e
Right (fromIntegral -> p) ->
let d = Bits.bit @t p
in mkNode opts (Val d) (msg0 <> " " <> showL opts p <> " = " <> showL opts d) [hh pp]
-- | create a 'Data.Bits.Bits' for type @t with all bits set to zero: similar to 'Data.Bits.zeroBits'
--
-- >>> pz @(ZeroBits Int) ()
-- Val 0
--
data ZeroBits t deriving Show
instance ( Show t
, Bits t
) => P (ZeroBits t) a where
type PP (ZeroBits t) a = t
eval _ opts _ = pure $
let msg0 = "ZeroBits"
d = Bits.zeroBits @t
in mkNode opts (Val d) (msg0 <> " " <> " = " <> showL opts d) []