#if __GLASGOW_HASKELL__ >= 705
#endif
#include "MachDeps.h"
module Data.BinaryWord
( BinaryWord(..)
, lMsb
, lLsb
) where
import Data.Int
import Data.Word
import Data.Bits (Bits(..))
#if MIN_VERSION_base(4,7,0)
import Data.Bits (FiniteBits(..))
#endif
#if __GLASGOW_HASKELL__ >= 705
import GHC.Prim (plusWord2#, timesWord2#)
# if WORD_SIZE_IN_BITS == 32
import GHC.Word (Word32(..))
# endif
# if WORD_SIZE_IN_BITS == 64
import GHC.Word (Word64(..))
# endif
#endif
#if MIN_VERSION_base(4,7,0)
class (FiniteBits w, FiniteBits (UnsignedWord w), FiniteBits (SignedWord w))
#else
class (Bits w, Bits (UnsignedWord w), Bits (SignedWord w))
#endif
⇒ BinaryWord w where
type UnsignedWord w
type SignedWord w
unsignedWord ∷ w → UnsignedWord w
signedWord ∷ w → SignedWord w
unwrappedAdd ∷ w → w → (w, UnsignedWord w)
unwrappedMul ∷ w → w → (w, UnsignedWord w)
leadingZeroes ∷ w → Int
trailingZeroes ∷ w → Int
allZeroes ∷ w
allOnes ∷ w
msb ∷ w
lsb ∷ w
lsb = bit 0
testMsb ∷ w → Bool
testLsb ∷ w → Bool
testLsb = flip testBit 0
setMsb ∷ w → w
setLsb ∷ w → w
setLsb = flip setBit 0
clearMsb ∷ w → w
clearLsb ∷ w → w
clearLsb = flip clearBit 0
lMsb ∷ (Functor f, BinaryWord w) ⇒ (Bool → f Bool) → w → f w
lMsb f w = fmap (\x → if x then setMsb w else clearMsb w) (f (testMsb w))
lLsb ∷ (Functor f, BinaryWord w) ⇒ (Bool → f Bool) → w → f w
lLsb f w = fmap (\x → if x then setLsb w else clearLsb w) (f (testLsb w))
instance BinaryWord Word8 where
type UnsignedWord Word8 = Word8
type SignedWord Word8 = Int8
unsignedWord = id
signedWord = fromIntegral
unwrappedAdd x y = hi `seq` lo `seq` (hi, lo)
where s = fromIntegral x + fromIntegral y ∷ Word16
lo = fromIntegral s
hi = fromIntegral (shiftR s 8)
unwrappedMul x y = hi `seq` lo `seq` (hi, lo)
where p = fromIntegral x * fromIntegral y ∷ Word16
lo = fromIntegral p
hi = fromIntegral (shiftR p 8)
#if MIN_VERSION_base(4,8,0)
leadingZeroes = countLeadingZeros
trailingZeroes = countTrailingZeros
#else
leadingZeroes w | w .&. 0xF0 == 0 = go4 4 w
| otherwise = go4 0 (shiftR w 4)
where go4 off w' | w' .&. 8 /= 0 = off
| w' .&. 4 /= 0 = off + 1
| w' .&. 2 /= 0 = off + 2
| w' .&. 1 /= 0 = off + 3
| otherwise = off + 4
trailingZeroes w | w .&. 0x0F == 0 = go4 4 (shiftR w 4)
| otherwise = go4 0 w
where go4 off w' | w' .&. 1 /= 0 = off
| w' .&. 2 /= 0 = off + 1
| w' .&. 4 /= 0 = off + 2
| w' .&. 8 /= 0 = off + 3
| otherwise = off + 4
#endif
allZeroes = 0
allOnes = 0xFF
msb = 0x80
lsb = 1
testMsb x = testBit x 7
setMsb x = setBit x 7
clearMsb x = clearBit x 7
instance BinaryWord Word16 where
type UnsignedWord Word16 = Word16
type SignedWord Word16 = Int16
unsignedWord = id
signedWord = fromIntegral
unwrappedAdd x y = hi `seq` lo `seq` (hi, lo)
where s = fromIntegral x + fromIntegral y ∷ Word32
lo = fromIntegral s
hi = fromIntegral (shiftR s 16)
unwrappedMul x y = hi `seq` lo `seq` (hi, lo)
where p = fromIntegral x * fromIntegral y ∷ Word32
lo = fromIntegral p
hi = fromIntegral (shiftR p 16)
#if MIN_VERSION_base(4,8,0)
leadingZeroes = countLeadingZeros
trailingZeroes = countTrailingZeros
#else
leadingZeroes w | w .&. 0xFF00 == 0 = go8 8 w
| otherwise = go8 0 (shiftR w 8)
where
go8 off w' | w' .&. 0xF0 == 0 = go4 (off + 4) w'
| otherwise = go4 off (shiftR w' 4)
go4 off w' | w' .&. 8 /= 0 = off
| w' .&. 4 /= 0 = off + 1
| w' .&. 2 /= 0 = off + 2
| w' .&. 1 /= 0 = off + 3
| otherwise = off + 4
trailingZeroes w | w .&. 0x00FF == 0 = go8 8 (shiftR w 8)
| otherwise = go8 0 w
where
go8 off w' | w' .&. 0x0F == 0 = go4 (off + 4) (shiftR w' 4)
| otherwise = go4 off w'
go4 off w' | w' .&. 1 /= 0 = off
| w' .&. 2 /= 0 = off + 1
| w' .&. 4 /= 0 = off + 2
| w' .&. 8 /= 0 = off + 3
| otherwise = off + 4
#endif
allZeroes = 0
allOnes = 0xFFFF
msb = 0x8000
lsb = 1
testMsb x = testBit x 15
setMsb x = setBit x 15
clearMsb x = clearBit x 15
instance BinaryWord Word32 where
type UnsignedWord Word32 = Word32
type SignedWord Word32 = Int32
unsignedWord = id
signedWord = fromIntegral
#if __GLASGOW_HASKELL__ >= 705 && WORD_SIZE_IN_BITS == 32
unwrappedAdd (W32# x) (W32# y) = hi `seq` lo `seq` (hi, lo)
where (# hi', lo' #) = plusWord2# x y
lo = W32# lo'
hi = W32# hi'
#else
unwrappedAdd x y = hi `seq` lo `seq` (hi, lo)
where s = fromIntegral x + fromIntegral y ∷ Word64
lo = fromIntegral s
hi = fromIntegral (shiftR s 32)
#endif
#if __GLASGOW_HASKELL__ >= 705 && WORD_SIZE_IN_BITS == 32
unwrappedMul (W32# x) (W32# y) = hi `seq` lo `seq` (hi, lo)
where (# hi', lo' #) = timesWord2# x y
lo = W32# lo'
hi = W32# hi'
#else
unwrappedMul x y = hi `seq` lo `seq` (hi, lo)
where p = fromIntegral x * fromIntegral y ∷ Word64
lo = fromIntegral p
hi = fromIntegral (shiftR p 32)
#endif
#if MIN_VERSION_base(4,8,0)
leadingZeroes = countLeadingZeros
trailingZeroes = countTrailingZeros
#else
leadingZeroes w | w .&. 0xFFFF0000 == 0 = go16 16 w
| otherwise = go16 0 (shiftR w 16)
where
go16 off w' | w' .&. 0xFF00 == 0 = go8 (off + 8) w'
| otherwise = go8 off (shiftR w' 8)
go8 off w' | w' .&. 0xF0 == 0 = go4 (off + 4) w'
| otherwise = go4 off (shiftR w' 4)
go4 off w' | w' .&. 8 /= 0 = off
| w' .&. 4 /= 0 = off + 1
| w' .&. 2 /= 0 = off + 2
| w' .&. 1 /= 0 = off + 3
| otherwise = off + 4
trailingZeroes w | w .&. 0x0000FFFF == 0 = go16 16 (shiftR w 16)
| otherwise = go16 0 w
where
go16 off w' | w' .&. 0x00FF == 0 = go8 (off + 8) (shiftR w' 8)
| otherwise = go8 off w'
go8 off w' | w' .&. 0x0F == 0 = go4 (off + 4) (shiftR w' 4)
| otherwise = go4 off w'
go4 off w' | w' .&. 1 /= 0 = off
| w' .&. 2 /= 0 = off + 1
| w' .&. 4 /= 0 = off + 2
| w' .&. 8 /= 0 = off + 3
| otherwise = off + 4
#endif
allZeroes = 0
allOnes = 0xFFFFFFFF
msb = 0x80000000
lsb = 1
testMsb x = testBit x 31
setMsb x = setBit x 31
clearMsb x = clearBit x 31
instance BinaryWord Word64 where
type UnsignedWord Word64 = Word64
type SignedWord Word64 = Int64
unsignedWord = id
signedWord = fromIntegral
#if __GLASGOW_HASKELL__ >= 705 && WORD_SIZE_IN_BITS == 64
unwrappedAdd (W64# x) (W64# y) = hi `seq` lo `seq` (hi, lo)
where (# hi', lo' #) = plusWord2# x y
lo = W64# lo'
hi = W64# hi'
#else
unwrappedAdd x y = hi `seq` lo `seq` (hi, lo)
where lo = x + y
hi = if lo < x then 1 else 0
#endif
#if __GLASGOW_HASKELL__ >= 705 && WORD_SIZE_IN_BITS == 64
unwrappedMul (W64# x) (W64# y) = hi `seq` lo `seq` (hi, lo)
where (# hi', lo' #) = timesWord2# x y
lo = W64# lo'
hi = W64# hi'
#else
unwrappedMul x y = hi `seq` lo `seq` (hi, lo)
where xHi = shiftR x 32
xLo = x .&. 0xFFFFFFFF
yHi = shiftR y 32
yLo = y .&. 0xFFFFFFFF
hi0 = xHi * yHi
lo0 = xLo * yLo
p1 = xHi * yLo
p2 = xLo * yHi
hi = hi0 + fromIntegral (uHi1 ∷ Word32) + fromIntegral uHi2 +
shiftR p1 32 + shiftR p2 32
lo = shiftL (fromIntegral lo') 32 .|. (lo0 .&. 0xFFFFFFFF)
(uHi1, uLo) = unwrappedAdd (fromIntegral p1) (fromIntegral p2)
(uHi2, lo') = unwrappedAdd (fromIntegral (shiftR lo0 32)) uLo
#endif
#if MIN_VERSION_base(4,8,0)
leadingZeroes = countLeadingZeros
trailingZeroes = countTrailingZeros
#else
# if WORD_SIZE_IN_BITS == 64
leadingZeroes w | w .&. 0xFFFFFFFF00000000 == 0 = go32 32 w
| otherwise = go32 0 (shiftR w 32)
where
go32 off w' | w' .&. 0xFFFF0000 == 0 = go16 (off + 16) w'
| otherwise = go16 off (shiftR w' 16)
go16 off w' | w' .&. 0xFF00 == 0 = go8 (off + 8) w'
| otherwise = go8 off (shiftR w' 8)
go8 off w' | w' .&. 0xF0 == 0 = go4 (off + 4) w'
| otherwise = go4 off (shiftR w' 4)
go4 off w' | w' .&. 8 /= 0 = off
| w' .&. 4 /= 0 = off + 1
| w' .&. 2 /= 0 = off + 2
| w' .&. 1 /= 0 = off + 3
| otherwise = off + 4
trailingZeroes w | w .&. 0x00000000FFFFFFFF == 0 = go32 32 (shiftR w 32)
| otherwise = go32 0 w
where
go32 off w' | w' .&. 0x0000FFFF == 0 = go16 (off + 16) (shiftR w' 16)
| otherwise = go16 off w'
go16 off w' | w' .&. 0x00FF == 0 = go8 (off + 8) (shiftR w' 8)
| otherwise = go8 off w'
go8 off w' | w' .&. 0x0F == 0 = go4 (off + 4) (shiftR w' 4)
| otherwise = go4 off w'
go4 off w' | w' .&. 1 /= 0 = off
| w' .&. 2 /= 0 = off + 1
| w' .&. 4 /= 0 = off + 2
| w' .&. 8 /= 0 = off + 3
| otherwise = off + 4
# else
leadingZeroes w | hiZeroes == 32 = 32 + leadingZeroes lo
| otherwise = hiZeroes
where lo = fromIntegral w ∷ Word32
hi = fromIntegral (shiftR w 32) ∷ Word32
hiZeroes = leadingZeroes hi
trailingZeroes w | loZeroes == 32 = 32 + trailingZeroes hi
| otherwise = loZeroes
where lo = fromIntegral w ∷ Word32
hi = fromIntegral (shiftR w 32) ∷ Word32
loZeroes = trailingZeroes lo
# endif
#endif
allZeroes = 0
allOnes = 0xFFFFFFFFFFFFFFFF
msb = 0x8000000000000000
lsb = 1
testMsb x = testBit x 63
setMsb x = setBit x 63
clearMsb x = clearBit x 63
instance BinaryWord Int8 where
type UnsignedWord Int8 = Word8
type SignedWord Int8 = Int8
unsignedWord = fromIntegral
signedWord = id
unwrappedAdd x y = hi `seq` lo `seq` (hi, lo)
where s = fromIntegral x + fromIntegral y ∷ Int16
lo = fromIntegral s
hi = fromIntegral (shiftR s 8)
unwrappedMul x y = hi `seq` lo `seq` (hi, lo)
where p = fromIntegral x * fromIntegral y ∷ Int16
lo = fromIntegral p
hi = fromIntegral (shiftR p 8)
leadingZeroes = leadingZeroes . unsignedWord
trailingZeroes = trailingZeroes . unsignedWord
allZeroes = 0
allOnes = 1
msb = minBound
lsb = 1
testMsb x = testBit x 7
setMsb x = setBit x 7
clearMsb x = clearBit x 7
instance BinaryWord Int16 where
type UnsignedWord Int16 = Word16
type SignedWord Int16 = Int16
unsignedWord = fromIntegral
signedWord = id
unwrappedAdd x y = hi `seq` lo `seq` (hi, lo)
where s = fromIntegral x + fromIntegral y ∷ Int32
lo = fromIntegral s
hi = fromIntegral (shiftR s 16)
unwrappedMul x y = hi `seq` lo `seq` (hi, lo)
where p = fromIntegral x * fromIntegral y ∷ Int32
lo = fromIntegral p
hi = fromIntegral (shiftR p 16)
leadingZeroes = leadingZeroes . unsignedWord
trailingZeroes = trailingZeroes . unsignedWord
allZeroes = 0
allOnes = 1
msb = minBound
lsb = 1
testMsb x = testBit x 15
setMsb x = setBit x 15
clearMsb x = clearBit x 15
instance BinaryWord Int32 where
type UnsignedWord Int32 = Word32
type SignedWord Int32 = Int32
unsignedWord = fromIntegral
signedWord = id
#if WORD_SIZE_IN_BITS == 32
unwrappedAdd x y = hi `seq` lo `seq` (hi, lo)
where extX = if x < 0 then maxBound else 0
extY = if y < 0 then maxBound else 0
(hi', lo) = unsignedWord x `unwrappedAdd` unsignedWord y
hi = signedWord $ hi' + extX + extY
unwrappedMul x y = hi `seq` lo `seq` (hi, lo)
where extX = if x < 0 then negate y else 0
extY = if y < 0 then negate x else 0
(hi', lo) = unsignedWord x `unwrappedMul` unsignedWord y
hi = signedWord hi' + extX + extY
#else
unwrappedAdd x y = hi `seq` lo `seq` (hi, lo)
where s = fromIntegral x + fromIntegral y ∷ Int64
lo = fromIntegral s
hi = fromIntegral (shiftR s 32)
unwrappedMul x y = hi `seq` lo `seq` (hi, lo)
where p = fromIntegral x * fromIntegral y ∷ Int64
lo = fromIntegral p
hi = fromIntegral (shiftR p 32)
#endif
leadingZeroes = leadingZeroes . unsignedWord
trailingZeroes = trailingZeroes . unsignedWord
allZeroes = 0
allOnes = 1
msb = minBound
lsb = 1
testMsb x = testBit x 31
setMsb x = setBit x 31
clearMsb x = clearBit x 31
instance BinaryWord Int64 where
type UnsignedWord Int64 = Word64
type SignedWord Int64 = Int64
unsignedWord = fromIntegral
signedWord = id
unwrappedAdd x y = hi `seq` lo `seq` (hi, lo)
where extX = if x < 0 then maxBound else 0
extY = if y < 0 then maxBound else 0
(hi', lo) = unsignedWord x `unwrappedAdd` unsignedWord y
hi = signedWord $ hi' + extX + extY
unwrappedMul x y = hi `seq` lo `seq` (hi, lo)
where extX = if x < 0 then negate y else 0
extY = if y < 0 then negate x else 0
(hi', lo) = unsignedWord x `unwrappedMul` unsignedWord y
hi = signedWord hi' + extX + extY
leadingZeroes = leadingZeroes . unsignedWord
trailingZeroes = trailingZeroes . unsignedWord
allZeroes = 0
allOnes = 1
msb = minBound
lsb = 1
testMsb x = testBit x 63
setMsb x = setBit x 63
clearMsb x = clearBit x 63