{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DataKinds #-}
module Haskus.Binary.Bits
( Bits
, FiniteBits (..)
, IndexableBits (..)
, ShiftableBits (..)
, SignedShiftableBits (..)
, RotatableBits (..)
, Bitwise (..)
, ReversableBits (..)
, reverseBitsGeneric
, reverseLeastBits
, MaskBits (..)
, Maskable
, maskDyn
, mask
, bitsToString
, bitsToStringN
, bitsFromString
, getBitRange
, bitOffset
, byteOffset
, isPowerOfTwo
, isPowerOfFour
, getPowerOfTwo
, getPowerOfFour
)
where
import Haskus.Utils.List (foldl')
import Haskus.Utils.Types
import Haskus.Utils.Maybe
import Haskus.Binary.Bits.Finite
import Haskus.Binary.Bits.Index
import Haskus.Binary.Bits.Reverse
import Haskus.Binary.Bits.Rotate
import Haskus.Binary.Bits.Shift
import Haskus.Binary.Bits.Bitwise
import Haskus.Binary.Bits.Order
import Haskus.Binary.Bits.Mask
import Haskus.Binary.Bits.Helper
type Bits a =
( Eq a
, FiniteBits a
, IndexableBits a
, ShiftableBits a
, Bitwise a
, RotatableBits a
, KnownNat (BitSize a)
, MaskBits a
)
isPowerOfTwo :: IndexableBits a => a -> Bool
isPowerOfTwo x = popCount x == 1
getPowerOfTwo :: (IndexableBits a, FiniteBits a) => a -> Maybe Word
getPowerOfTwo x
| isPowerOfTwo x = Just (countTrailingZeros x)
| otherwise = Nothing
isPowerOfFour :: (IndexableBits a, FiniteBits a) => a -> Bool
isPowerOfFour x = isJust (getPowerOfFour x)
getPowerOfFour :: (IndexableBits a, FiniteBits a) => a -> Maybe Word
getPowerOfFour x
| popCount x == 1
, let c = countTrailingZeros x
, testBit c 0 == False
= Just (c `shiftR` 1)
| otherwise = Nothing
reverseLeastBits ::
( ShiftableBits a
, FiniteBits a
, ReversableBits a
, KnownNat (BitSize a)
) => Word -> a -> a
reverseLeastBits n value = reverseBits value `uncheckedShiftR` ((bitSize value) - n)
bitsToString :: forall a.
( FiniteBits a
, IndexableBits a
, KnownNat (BitSize a)
) => a -> String
bitsToString = bitsToStringN (natValue @(BitSize a))
bitsToStringN :: forall a.
( IndexableBits a
) => Word -> a -> String
bitsToStringN n x = fmap b [n-1, n-2 .. 0]
where
b v = if testBit x v then '1' else '0'
bitsFromString :: Bits a => String -> a
bitsFromString xs = foldl' b zeroBits (reverse xs `zip` [0..])
where
b x ('0',i) = clearBit x i
b x ('1',i) = setBit x i
b _ (c,_) = error $ "Invalid character in the string: " ++ [c]
getBitRange :: forall b.
( ShiftableBits b
, ReversableBits b
, FiniteBits b
, KnownNat (BitSize b)
, Bitwise b
, MaskBits b
) => BitOrder -> Word -> Word -> b -> b
{-# INLINABLE getBitRange #-}
getBitRange bo o n c = case bo of
BB -> maskDyn n $ c `uncheckedShiftR` d
BL -> maskDyn n $ reverseBits c `uncheckedShiftR` o
LB -> maskDyn n $ reverseBits c `uncheckedShiftR` d
LL -> maskDyn n $ c `uncheckedShiftR` o
where
d = bitSize c - n - o