bitwise-0.1.0.1: src/Data/Array/BitArray/Internal.hs
{-# OPTIONS_HADDOCK hide #-}
{-|
Module : Data.Array.BitArray.Internal
Copyright : (c) Claude Heiland-Allen 2012
License : BSD3
Maintainer : claude@mathr.co.uk
Stability : unstable
Portability : portable
Bit arrays internals. Not exposed.
-}
module Data.Array.BitArray.Internal
( BitArray(..)
, IOBitArray(..)
, getBounds
, newArray_
, freeze
, thaw
, copy
, unsafeFreeze
, unsafeThaw
) where
import Data.Bits (shiftL, shiftR)
import Data.Ix (Ix, rangeSize)
import Data.Word (Word64)
import Foreign.Marshal.Utils (copyBytes)
import Foreign.ForeignPtr (ForeignPtr, mallocForeignPtrBytes, withForeignPtr)
-- | The type of immutable bit arrays.
newtype BitArray i = B (IOBitArray i)
-- | The type of mutable bit arrays in the 'IO' monad.
data IOBitArray i = IOB{ iobBoundLo :: !i, iobBoundHi :: !i, iobBytes :: {-# UNPACK #-} !Int, iobData :: {-# UNPACK #-} !(ForeignPtr Word64) }
-- | Create a new array filled with unspecified initial values.
{-# INLINE newArray_ #-}
newArray_ :: Ix i => (i, i) {- ^ bounds -} -> IO (IOBitArray i)
newArray_ bs@(bl, bh) = do
let bits = rangeSize bs
nwords = (bits + 63) `shiftR` 6
bytes = nwords `shiftL` 3
p <- mallocForeignPtrBytes bytes
return IOB{ iobBoundLo = bl, iobBoundHi = bh, iobBytes = bytes, iobData = p }
-- | Get the bounds of a bit array.
{-# INLINE getBounds #-}
getBounds :: Ix i => IOBitArray i -> IO (i, i)
getBounds a = return (iobBoundLo a, iobBoundHi a)
-- | Snapshot the array into an immutable form.
{-# INLINE freeze #-}
freeze :: Ix i => IOBitArray i -> IO (BitArray i)
freeze a = B `fmap` copy a
-- | Snapshot the array into an immutable form. Unsafe when the source
-- array can be modified later.
{-# INLINE unsafeFreeze #-}
unsafeFreeze :: Ix i => IOBitArray i -> IO (BitArray i)
unsafeFreeze a = B `fmap` return a
-- | Convert an array from immutable form.
{-# INLINE thaw #-}
thaw :: Ix i => BitArray i -> IO (IOBitArray i)
thaw (B a) = copy a
-- | Convert an array from immutable form. Unsafe to modify the result
-- unless the source array is never used later.
{-# INLINE unsafeThaw #-}
unsafeThaw :: Ix i => BitArray i -> IO (IOBitArray i)
unsafeThaw (B a) = return a
-- | Copy an array.
{-# INLINE copy #-}
copy :: Ix i => IOBitArray i -> IO (IOBitArray i)
copy a = do
b <- newArray_ =<< getBounds a
withForeignPtr (iobData a) $ \ap ->
withForeignPtr (iobData b) $ \bp ->
copyBytes bp ap (iobBytes b)
return b