{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
#ifndef BITVEC_THREADSAFE
module Data.Bit.Mutable
#else
module Data.Bit.MutableTS
#endif
( castFromWordsM
, castToWordsM
, cloneToWordsM
, zipInPlace
, invertInPlace
, selectBitsInPlace
, excludeBitsInPlace
, reverseInPlace
) where
import Control.Monad
import Control.Monad.Primitive
#ifndef BITVEC_THREADSAFE
import Data.Bit.Internal
#else
import Data.Bit.InternalTS
#endif
import Data.Bit.Utils
import Data.Bits
import qualified Data.Vector.Generic.Mutable as MV
import qualified Data.Vector.Generic as V
import qualified Data.Vector.Unboxed as U (Vector)
import Data.Vector.Unboxed.Mutable as U
import Data.Word
import Prelude as P
hiding (and, or, any, all, reverse)
castFromWordsM
:: U.MVector s Word
-> U.MVector s Bit
castFromWordsM ws = BitMVec 0 (nBits (MV.length ws)) ws
castToWordsM
:: U.MVector s Bit
-> Maybe (U.MVector s Word)
castToWordsM (BitMVec s n ws)
| aligned s
, aligned n
= Just $ MV.slice (divWordSize s) (nWords n) ws
| otherwise
= Nothing
cloneToWordsM
:: PrimMonad m
=> U.MVector (PrimState m) Bit
-> m (U.MVector (PrimState m) Word)
cloneToWordsM v@(BitMVec _ n _) = do
ws <- MV.new (nWords n)
let loop !i !j
| i >= n = return ()
| otherwise = do
readWord v i >>= MV.write ws j
loop (i + wordSize) (j + 1)
loop 0 0
return ws
{-# INLINE cloneToWordsM #-}
{-# INLINE mapMInPlaceWithIndex #-}
mapMInPlaceWithIndex ::
PrimMonad m =>
(Int -> Word -> m Word)
-> U.MVector (PrimState m) Bit -> m ()
mapMInPlaceWithIndex f xs@(BitMVec 0 _ v) = loop 0 0
where
!n_ = alignDown (MV.length xs)
loop !i !j
| i >= n_ = when (n_ /= MV.length xs) $ do
readWord xs i >>= f i >>= writeWord xs i
| otherwise = do
MV.read v j >>= f i >>= MV.write v j
loop (i + wordSize) (j + 1)
mapMInPlaceWithIndex f xs = loop 0
where
!n = MV.length xs
loop !i
| i >= n = return ()
| otherwise = do
readWord xs i >>= f i >>= writeWord xs i
loop (i + wordSize)
{-# INLINE mapInPlaceWithIndex #-}
mapInPlaceWithIndex ::
PrimMonad m =>
(Int -> Word -> Word)
-> U.MVector (PrimState m) Bit -> m ()
mapInPlaceWithIndex f = mapMInPlaceWithIndex g
where
{-# INLINE g #-}
g i x = return $! f i x
{-# INLINE mapInPlace #-}
mapInPlace :: PrimMonad m => (Word -> Word) -> U.MVector (PrimState m) Bit -> m ()
mapInPlace f = mapMInPlaceWithIndex (\_ x -> return (f x))
zipInPlace
:: PrimMonad m
=> (forall a. Bits a => a -> a -> a)
-> U.Vector Bit
-> U.MVector (PrimState m) Bit
-> m ()
zipInPlace f ys@(BitVec 0 n2 v) xs =
mapInPlaceWithIndex g (MV.basicUnsafeSlice 0 n xs)
where
!n = min (MV.length xs) (V.length ys)
{-# INLINE g #-}
g !i !x =
let !w = masked (n2 - i) (v V.! divWordSize i)
in f w x
zipInPlace f ys xs =
mapInPlaceWithIndex g (MV.basicUnsafeSlice 0 n xs)
where
!n = min (MV.length xs) (V.length ys)
{-# INLINE g #-}
g !i !x =
let !w = indexWord ys i
in f w x
{-# INLINE zipInPlace #-}
invertInPlace :: PrimMonad m => U.MVector (PrimState m) Bit -> m ()
invertInPlace = mapInPlace complement
selectBitsInPlace
:: PrimMonad m
=> U.Vector Bit
-> U.MVector (PrimState m) Bit
-> m Int
selectBitsInPlace is xs = loop 0 0
where
!n = min (V.length is) (MV.length xs)
loop !i !ct
| i >= n = return ct
| otherwise = do
x <- readWord xs i
let !(nSet, x') = selectWord (masked (n - i) (indexWord is i)) x
writeWord xs ct x'
loop (i + wordSize) (ct + nSet)
excludeBitsInPlace :: PrimMonad m => U.Vector Bit -> U.MVector (PrimState m) Bit -> m Int
excludeBitsInPlace is xs = loop 0 0
where
!n = min (V.length is) (MV.length xs)
loop !i !ct
| i >= n = return ct
| otherwise = do
x <- readWord xs i
let !(nSet, x') = selectWord (masked (n - i) (complement (indexWord is i))) x
writeWord xs ct x'
loop (i + wordSize) (ct + nSet)
reverseInPlace :: PrimMonad m => U.MVector (PrimState m) Bit -> m ()
reverseInPlace xs = loop 0 (MV.length xs)
where
loop !i !j
| i' <= j' = do
x <- readWord xs i
y <- readWord xs j'
writeWord xs i (reverseWord y)
writeWord xs j' (reverseWord x)
loop i' j'
| i' < j = do
let w = (j - i) `shiftR` 1
k = j - w
x <- readWord xs i
y <- readWord xs k
writeWord xs i (meld w (reversePartialWord w y) x)
writeWord xs k (meld w (reversePartialWord w x) y)
loop i' j'
| i < j = do
let w = j - i
x <- readWord xs i
writeWord xs i (meld w (reversePartialWord w x) x)
| otherwise = return ()
where
!i' = i + wordSize
!j' = j - wordSize