{-# LANGUAGE CPP, DeriveDataTypeable, FlexibleInstances, MagicHash, MultiParamTypeClasses, ScopedTypeVariables #-}
module Data.Vector.Storable.Mutable(
MVector(..), IOVector, STVector, Storable,
length, null,
slice, init, tail, take, drop, splitAt,
unsafeSlice, unsafeInit, unsafeTail, unsafeTake, unsafeDrop,
overlaps,
new, unsafeNew, replicate, replicateM, clone,
grow, unsafeGrow,
clear,
read, write, modify, swap,
unsafeRead, unsafeWrite, unsafeModify, unsafeSwap,
set, copy, move, unsafeCopy, unsafeMove,
unsafeCast,
unsafeFromForeignPtr, unsafeFromForeignPtr0,
unsafeToForeignPtr, unsafeToForeignPtr0,
unsafeWith
) where
import Control.DeepSeq ( NFData(rnf) )
import qualified Data.Vector.Generic.Mutable as G
import Data.Vector.Storable.Internal
import Foreign.Storable
import Foreign.ForeignPtr
#if __GLASGOW_HASKELL__ >= 706
import GHC.ForeignPtr (mallocPlainForeignPtrAlignedBytes)
#elif __GLASGOW_HASKELL__ >= 700
import Data.Primitive.ByteArray (MutableByteArray(..), newAlignedPinnedByteArray,
unsafeFreezeByteArray)
import GHC.Prim (byteArrayContents#, unsafeCoerce#)
import GHC.ForeignPtr
#endif
import GHC.Base ( Int(..) )
import Foreign.Ptr
import Foreign.Marshal.Array ( advancePtr, copyArray, moveArray )
import Control.Monad.Primitive
import Data.Primitive.Types (Prim)
import qualified Data.Primitive.Types as DPT
import GHC.Word (Word8, Word16, Word32, Word64)
import GHC.Ptr (Ptr(..))
import Prelude hiding ( length, null, replicate, reverse, map, read,
take, drop, splitAt, init, tail )
import Data.Typeable ( Typeable )
#define NOT_VECTOR_MODULE
#include "vector.h"
data MVector s a = MVector {-# UNPACK #-} !Int
{-# UNPACK #-} !(ForeignPtr a)
deriving ( Typeable )
type IOVector = MVector RealWorld
type STVector s = MVector s
instance NFData (MVector s a) where
rnf (MVector _ _) = ()
instance Storable a => G.MVector MVector a where
{-# INLINE basicLength #-}
basicLength (MVector n _) = n
{-# INLINE basicUnsafeSlice #-}
basicUnsafeSlice j m (MVector _ fp) = MVector m (updPtr (`advancePtr` j) fp)
{-# INLINE basicOverlaps #-}
basicOverlaps (MVector m fp) (MVector n fq)
= between p q (q `advancePtr` n) || between q p (p `advancePtr` m)
where
between x y z = x >= y && x < z
p = getPtr fp
q = getPtr fq
{-# INLINE basicUnsafeNew #-}
basicUnsafeNew n
| n < 0 = error $ "Storable.basicUnsafeNew: negative length: " ++ show n
| n > mx = error $ "Storable.basicUnsafeNew: length too large: " ++ show n
| otherwise = unsafePrimToPrim $ do
fp <- mallocVector n
return $ MVector n fp
where
size = sizeOf (undefined :: a)
mx = maxBound `quot` size :: Int
{-# INLINE basicInitialize #-}
basicInitialize = storableZero
{-# INLINE basicUnsafeRead #-}
basicUnsafeRead (MVector _ fp) i
= unsafePrimToPrim
$ withForeignPtr fp (`peekElemOff` i)
{-# INLINE basicUnsafeWrite #-}
basicUnsafeWrite (MVector _ fp) i x
= unsafePrimToPrim
$ withForeignPtr fp $ \p -> pokeElemOff p i x
{-# INLINE basicSet #-}
basicSet = storableSet
{-# INLINE basicUnsafeCopy #-}
basicUnsafeCopy (MVector n fp) (MVector _ fq)
= unsafePrimToPrim
$ withForeignPtr fp $ \p ->
withForeignPtr fq $ \q ->
copyArray p q n
{-# INLINE basicUnsafeMove #-}
basicUnsafeMove (MVector n fp) (MVector _ fq)
= unsafePrimToPrim
$ withForeignPtr fp $ \p ->
withForeignPtr fq $ \q ->
moveArray p q n
storableZero :: forall a m. (Storable a, PrimMonad m) => MVector (PrimState m) a -> m ()
{-# INLINE storableZero #-}
storableZero (MVector n fp) = unsafePrimToPrim . withForeignPtr fp $ \ptr-> do
memsetPrimPtr_vector (castPtr ptr) byteSize (0 :: Word8)
where
x :: a
x = undefined
byteSize :: Int
byteSize = n * sizeOf x
storableSet :: (Storable a, PrimMonad m) => MVector (PrimState m) a -> a -> m ()
{-# INLINE storableSet #-}
storableSet (MVector n fp) x
| n == 0 = return ()
| otherwise = unsafePrimToPrim $
case sizeOf x of
1 -> storableSetAsPrim n fp x (undefined :: Word8)
2 -> storableSetAsPrim n fp x (undefined :: Word16)
4 -> storableSetAsPrim n fp x (undefined :: Word32)
8 -> storableSetAsPrim n fp x (undefined :: Word64)
_ -> withForeignPtr fp $ \p -> do
poke p x
let do_set i
| 2*i < n = do
copyArray (p `advancePtr` i) p i
do_set (2*i)
| otherwise = copyArray (p `advancePtr` i) p (n-i)
do_set 1
storableSetAsPrim
:: forall a b . (Storable a, Prim b) => Int -> ForeignPtr a -> a -> b -> IO ()
{-# INLINE [0] storableSetAsPrim #-}
storableSetAsPrim n fp x _y = withForeignPtr fp $ \ ptr -> do
poke ptr x
w<- peakPrimPtr_vector ((castPtr ptr) :: Ptr b) 0
memsetPrimPtr_vector ((castPtr ptr) `plusPtr` sizeOf x ) (n-1) w
memsetPrimPtr_vector :: forall a c m. (Prim c, PrimMonad m) => Ptr a -> Int -> c -> m ()
memsetPrimPtr_vector (Ptr addr#) (I# n#) x = primitive_ (DPT.setOffAddr# addr# 0# n# x)
{-# INLINE memsetPrimPtr_vector #-}
peakPrimPtr_vector :: (Prim a, PrimMonad m) => Ptr a -> Int -> m a
peakPrimPtr_vector (Ptr addr#) (I# i#) = primitive (DPT.readOffAddr# addr# i#)
{-# INLINE peakPrimPtr_vector #-}
{-# INLINE mallocVector #-}
mallocVector :: Storable a => Int -> IO (ForeignPtr a)
mallocVector =
#if __GLASGOW_HASKELL__ >= 706
doMalloc undefined
where
doMalloc :: Storable b => b -> Int -> IO (ForeignPtr b)
doMalloc dummy size =
mallocPlainForeignPtrAlignedBytes (size * sizeOf dummy) (alignment dummy)
#elif __GLASGOW_HASKELL__ >= 700
doMalloc undefined
where
doMalloc :: Storable b => b -> Int -> IO (ForeignPtr b)
doMalloc dummy size = do
arr@(MutableByteArray arr#) <- newAlignedPinnedByteArray arrSize arrAlign
newConcForeignPtr
(Ptr (byteArrayContents# (unsafeCoerce# arr#)))
(touch arr)
where
arrSize = size * sizeOf dummy
arrAlign = alignment dummy
#else
mallocForeignPtrArray
#endif
length :: Storable a => MVector s a -> Int
{-# INLINE length #-}
length = G.length
null :: Storable a => MVector s a -> Bool
{-# INLINE null #-}
null = G.null
slice :: Storable a => Int -> Int -> MVector s a -> MVector s a
{-# INLINE slice #-}
slice = G.slice
take :: Storable a => Int -> MVector s a -> MVector s a
{-# INLINE take #-}
take = G.take
drop :: Storable a => Int -> MVector s a -> MVector s a
{-# INLINE drop #-}
drop = G.drop
splitAt :: Storable a => Int -> MVector s a -> (MVector s a, MVector s a)
{-# INLINE splitAt #-}
splitAt = G.splitAt
init :: Storable a => MVector s a -> MVector s a
{-# INLINE init #-}
init = G.init
tail :: Storable a => MVector s a -> MVector s a
{-# INLINE tail #-}
tail = G.tail
unsafeSlice :: Storable a
=> Int
-> Int
-> MVector s a
-> MVector s a
{-# INLINE unsafeSlice #-}
unsafeSlice = G.unsafeSlice
unsafeTake :: Storable a => Int -> MVector s a -> MVector s a
{-# INLINE unsafeTake #-}
unsafeTake = G.unsafeTake
unsafeDrop :: Storable a => Int -> MVector s a -> MVector s a
{-# INLINE unsafeDrop #-}
unsafeDrop = G.unsafeDrop
unsafeInit :: Storable a => MVector s a -> MVector s a
{-# INLINE unsafeInit #-}
unsafeInit = G.unsafeInit
unsafeTail :: Storable a => MVector s a -> MVector s a
{-# INLINE unsafeTail #-}
unsafeTail = G.unsafeTail
overlaps :: Storable a => MVector s a -> MVector s a -> Bool
{-# INLINE overlaps #-}
overlaps = G.overlaps
new :: (PrimMonad m, Storable a) => Int -> m (MVector (PrimState m) a)
{-# INLINE new #-}
new = G.new
unsafeNew :: (PrimMonad m, Storable a) => Int -> m (MVector (PrimState m) a)
{-# INLINE unsafeNew #-}
unsafeNew = G.unsafeNew
replicate :: (PrimMonad m, Storable a) => Int -> a -> m (MVector (PrimState m) a)
{-# INLINE replicate #-}
replicate = G.replicate
replicateM :: (PrimMonad m, Storable a) => Int -> m a -> m (MVector (PrimState m) a)
{-# INLINE replicateM #-}
replicateM = G.replicateM
clone :: (PrimMonad m, Storable a)
=> MVector (PrimState m) a -> m (MVector (PrimState m) a)
{-# INLINE clone #-}
clone = G.clone
grow :: (PrimMonad m, Storable a)
=> MVector (PrimState m) a -> Int -> m (MVector (PrimState m) a)
{-# INLINE grow #-}
grow = G.grow
unsafeGrow :: (PrimMonad m, Storable a)
=> MVector (PrimState m) a -> Int -> m (MVector (PrimState m) a)
{-# INLINE unsafeGrow #-}
unsafeGrow = G.unsafeGrow
clear :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> m ()
{-# INLINE clear #-}
clear = G.clear
read :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> m a
{-# INLINE read #-}
read = G.read
write
:: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> a -> m ()
{-# INLINE write #-}
write = G.write
modify :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> (a -> a) -> Int -> m ()
{-# INLINE modify #-}
modify = G.modify
swap
:: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> Int -> m ()
{-# INLINE swap #-}
swap = G.swap
unsafeRead :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> m a
{-# INLINE unsafeRead #-}
unsafeRead = G.unsafeRead
unsafeWrite
:: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> a -> m ()
{-# INLINE unsafeWrite #-}
unsafeWrite = G.unsafeWrite
unsafeModify :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> (a -> a) -> Int -> m ()
{-# INLINE unsafeModify #-}
unsafeModify = G.unsafeModify
unsafeSwap
:: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> Int -> m ()
{-# INLINE unsafeSwap #-}
unsafeSwap = G.unsafeSwap
set :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> a -> m ()
{-# INLINE set #-}
set = G.set
copy :: (PrimMonad m, Storable a)
=> MVector (PrimState m) a
-> MVector (PrimState m) a
-> m ()
{-# INLINE copy #-}
copy = G.copy
unsafeCopy :: (PrimMonad m, Storable a)
=> MVector (PrimState m) a
-> MVector (PrimState m) a
-> m ()
{-# INLINE unsafeCopy #-}
unsafeCopy = G.unsafeCopy
move :: (PrimMonad m, Storable a)
=> MVector (PrimState m) a -> MVector (PrimState m) a -> m ()
{-# INLINE move #-}
move = G.move
unsafeMove :: (PrimMonad m, Storable a)
=> MVector (PrimState m) a
-> MVector (PrimState m) a
-> m ()
{-# INLINE unsafeMove #-}
unsafeMove = G.unsafeMove
unsafeCast :: forall a b s.
(Storable a, Storable b) => MVector s a -> MVector s b
{-# INLINE unsafeCast #-}
unsafeCast (MVector n fp)
= MVector ((n * sizeOf (undefined :: a)) `div` sizeOf (undefined :: b))
(castForeignPtr fp)
unsafeFromForeignPtr :: Storable a
=> ForeignPtr a
-> Int
-> Int
-> MVector s a
{-# INLINE_FUSED unsafeFromForeignPtr #-}
unsafeFromForeignPtr fp i n = unsafeFromForeignPtr0 fp' n
where
fp' = updPtr (`advancePtr` i) fp
{-# RULES
"unsafeFromForeignPtr fp 0 n -> unsafeFromForeignPtr0 fp n " forall fp n.
unsafeFromForeignPtr fp 0 n = unsafeFromForeignPtr0 fp n #-}
unsafeFromForeignPtr0 :: Storable a
=> ForeignPtr a
-> Int
-> MVector s a
{-# INLINE unsafeFromForeignPtr0 #-}
unsafeFromForeignPtr0 fp n = MVector n fp
unsafeToForeignPtr :: Storable a => MVector s a -> (ForeignPtr a, Int, Int)
{-# INLINE unsafeToForeignPtr #-}
unsafeToForeignPtr (MVector n fp) = (fp, 0, n)
unsafeToForeignPtr0 :: Storable a => MVector s a -> (ForeignPtr a, Int)
{-# INLINE unsafeToForeignPtr0 #-}
unsafeToForeignPtr0 (MVector n fp) = (fp, n)
unsafeWith :: Storable a => IOVector a -> (Ptr a -> IO b) -> IO b
{-# INLINE unsafeWith #-}
unsafeWith (MVector _ fp) = withForeignPtr fp