{-# 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))