{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NoImplicitPrelude, MagicHash, ScopedTypeVariables #-}
module Foreign.Marshal.Array (
mallocArray,
mallocArray0,
allocaArray,
allocaArray0,
reallocArray,
reallocArray0,
callocArray,
callocArray0,
peekArray,
peekArray0,
pokeArray,
pokeArray0,
newArray,
newArray0,
withArray,
withArray0,
withArrayLen,
withArrayLen0,
copyArray,
moveArray,
lengthArray0,
advancePtr,
) where
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.Storable (Storable(alignment,sizeOf,peekElemOff,pokeElemOff))
import Foreign.Marshal.Alloc (mallocBytes, callocBytes, allocaBytesAligned, reallocBytes)
import Foreign.Marshal.Utils (copyBytes, moveBytes)
import GHC.Num
import GHC.List
import GHC.Base
mallocArray :: forall a . Storable a => Int -> IO (Ptr a)
mallocArray size = mallocBytes (size * sizeOf (undefined :: a))
mallocArray0 :: Storable a => Int -> IO (Ptr a)
mallocArray0 size = mallocArray (size + 1)
callocArray :: forall a . Storable a => Int -> IO (Ptr a)
callocArray size = callocBytes (size * sizeOf (undefined :: a))
callocArray0 :: Storable a => Int -> IO (Ptr a)
callocArray0 size = callocArray (size + 1)
allocaArray :: forall a b . Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray size = allocaBytesAligned (size * sizeOf (undefined :: a))
(alignment (undefined :: a))
allocaArray0 :: Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray0 size = allocaArray (size + 1)
{-# INLINE allocaArray0 #-}
reallocArray :: forall a . Storable a => Ptr a -> Int -> IO (Ptr a)
reallocArray ptr size = reallocBytes ptr (size * sizeOf (undefined :: a))
reallocArray0 :: Storable a => Ptr a -> Int -> IO (Ptr a)
reallocArray0 ptr size = reallocArray ptr (size + 1)
peekArray :: Storable a => Int -> Ptr a -> IO [a]
peekArray size ptr | size <= 0 = return []
| otherwise = f (size-1) []
where
f 0 acc = do e <- peekElemOff ptr 0; return (e:acc)
f n acc = do e <- peekElemOff ptr n; f (n-1) (e:acc)
peekArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO [a]
peekArray0 marker ptr = do
size <- lengthArray0 marker ptr
peekArray size ptr
pokeArray :: Storable a => Ptr a -> [a] -> IO ()
pokeArray ptr vals0 = go vals0 0#
where go [] _ = return ()
go (val:vals) n# = do pokeElemOff ptr (I# n#) val; go vals (n# +# 1#)
pokeArray0 :: Storable a => a -> Ptr a -> [a] -> IO ()
pokeArray0 marker ptr vals0 = go vals0 0#
where go [] n# = pokeElemOff ptr (I# n#) marker
go (val:vals) n# = do pokeElemOff ptr (I# n#) val; go vals (n# +# 1#)
newArray :: Storable a => [a] -> IO (Ptr a)
newArray vals = do
ptr <- mallocArray (length vals)
pokeArray ptr vals
return ptr
newArray0 :: Storable a => a -> [a] -> IO (Ptr a)
newArray0 marker vals = do
ptr <- mallocArray0 (length vals)
pokeArray0 marker ptr vals
return ptr
withArray :: Storable a => [a] -> (Ptr a -> IO b) -> IO b
withArray vals = withArrayLen vals . const
withArrayLen :: Storable a => [a] -> (Int -> Ptr a -> IO b) -> IO b
withArrayLen vals f =
allocaArray len $ \ptr -> do
pokeArray ptr vals
f len ptr
where
len = length vals
withArray0 :: Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b
withArray0 marker vals = withArrayLen0 marker vals . const
withArrayLen0 :: Storable a => a -> [a] -> (Int -> Ptr a -> IO b) -> IO b
withArrayLen0 marker vals f =
allocaArray0 len $ \ptr -> do
pokeArray0 marker ptr vals
res <- f len ptr
return res
where
len = length vals
copyArray :: forall a . Storable a => Ptr a -> Ptr a -> Int -> IO ()
copyArray dest src size = copyBytes dest src (size * sizeOf (undefined :: a))
moveArray :: forall a . Storable a => Ptr a -> Ptr a -> Int -> IO ()
moveArray dest src size = moveBytes dest src (size * sizeOf (undefined :: a))
lengthArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO Int
lengthArray0 marker ptr = loop 0
where
loop i = do
val <- peekElemOff ptr i
if val == marker then return i else loop (i+1)
advancePtr :: forall a . Storable a => Ptr a -> Int -> Ptr a
advancePtr ptr i = ptr `plusPtr` (i * sizeOf (undefined :: a))