module Bio.Utils.BitVector ( BitVector(..) , BitMVector , size , (!) , set , clear , unsafeFreeze , zeros , toList ) where import qualified Data.Vector.Unboxed as U import Control.Monad.Primitive import qualified Data.Vector.Unboxed.Mutable as UM import Data.Word import Data.Bits import Text.Printf (printf) data BitVector = BitVector Int (U.Vector Word8) data BitMVector s = BitMVector Int (UM.MVector s Word8) size :: BitVector -> Int size (BitVector n _) = n (!) :: BitVector -> Int -> Bool (!) = index index :: BitVector -> Int -> Bool index (BitVector n v) idx | idx >= n = error $ printf "index out of bounds (%d,%d)" idx n | otherwise = testBit (v `U.unsafeIndex` i) j where i = idx `div` 8 j = idx `mod` 8 set :: PrimMonad m => BitMVector (PrimState m) -> Int -> m () set (BitMVector _ mv) idx = UM.modify mv ((flip setBit) j) i where i = idx `div` 8 j = idx `mod` 8 clear :: PrimMonad m => BitMVector (PrimState m) -> Int -> m () clear (BitMVector _ mv) idx = UM.modify mv ((flip clearBit) j) i where i = idx `div` 8 j = idx `mod` 8 unsafeFreeze :: PrimMonad m => BitMVector (PrimState m) -> m BitVector unsafeFreeze (BitMVector n mv) = U.unsafeFreeze mv >>= return . BitVector n zeros :: PrimMonad m => Int -> m (BitMVector (PrimState m)) zeros n = UM.replicate n' 0 >>= return . BitMVector n where n' = if j == 0 then i else i + 1 i = n `div` 8 j = n `mod` 8 toList :: BitVector -> [Bool] toList bv = flip map [0..n-1] $ \i -> bv ! i where n = size bv