{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NoImplicitPrelude
, MagicHash
, UnboxedTuples
#-}
module Foreign.Marshal.Alloc (
alloca,
allocaBytes,
allocaBytesAligned,
malloc,
mallocBytes,
realloc,
reallocBytes,
free,
finalizerFree
) where
import Data.Maybe
import Foreign.C.Types ( CSize(..) )
import Foreign.Storable ( Storable(sizeOf,alignment) )
import Foreign.ForeignPtr ( FinalizerPtr )
import GHC.IO.Exception
import GHC.Real
import GHC.Ptr
import GHC.Base
{-# INLINE malloc #-}
malloc :: Storable a => IO (Ptr a)
malloc = doMalloc undefined
where
doMalloc :: Storable b => b -> IO (Ptr b)
doMalloc dummy = mallocBytes (sizeOf dummy)
mallocBytes :: Int -> IO (Ptr a)
mallocBytes size = failWhenNULL "malloc" (_malloc (fromIntegral size))
{-# INLINE alloca #-}
alloca :: Storable a => (Ptr a -> IO b) -> IO b
alloca = doAlloca undefined
where
doAlloca :: Storable a' => a' -> (Ptr a' -> IO b') -> IO b'
doAlloca dummy = allocaBytesAligned (sizeOf dummy) (alignment dummy)
allocaBytes :: Int -> (Ptr a -> IO b) -> IO b
allocaBytes (I# size) action = IO $ \ s0 ->
case newPinnedByteArray# size s0 of { (# s1, mbarr# #) ->
case unsafeFreezeByteArray# mbarr# s1 of { (# s2, barr# #) ->
let addr = Ptr (byteArrayContents# barr#) in
case action addr of { IO action' ->
case action' s2 of { (# s3, r #) ->
case touch# barr# s3 of { s4 ->
(# s4, r #)
}}}}}
allocaBytesAligned :: Int -> Int -> (Ptr a -> IO b) -> IO b
allocaBytesAligned (I# size) (I# align) action = IO $ \ s0 ->
case newAlignedPinnedByteArray# size align s0 of { (# s1, mbarr# #) ->
case unsafeFreezeByteArray# mbarr# s1 of { (# s2, barr# #) ->
let addr = Ptr (byteArrayContents# barr#) in
case action addr of { IO action' ->
case action' s2 of { (# s3, r #) ->
case touch# barr# s3 of { s4 ->
(# s4, r #)
}}}}}
realloc :: Storable b => Ptr a -> IO (Ptr b)
realloc = doRealloc undefined
where
doRealloc :: Storable b' => b' -> Ptr a' -> IO (Ptr b')
doRealloc dummy ptr = let
size = fromIntegral (sizeOf dummy)
in
failWhenNULL "realloc" (_realloc ptr size)
reallocBytes :: Ptr a -> Int -> IO (Ptr a)
reallocBytes ptr 0 = do free ptr; return nullPtr
reallocBytes ptr size =
failWhenNULL "realloc" (_realloc ptr (fromIntegral size))
free :: Ptr a -> IO ()
free = _free
failWhenNULL :: String -> IO (Ptr a) -> IO (Ptr a)
failWhenNULL name f = do
addr <- f
if addr == nullPtr
then ioError (IOError Nothing ResourceExhausted name
"out of memory" Nothing Nothing)
else return addr
foreign import ccall unsafe "stdlib.h malloc" _malloc :: CSize -> IO (Ptr a)
foreign import ccall unsafe "stdlib.h realloc" _realloc :: Ptr a -> CSize -> IO (Ptr b)
foreign import ccall unsafe "stdlib.h free" _free :: Ptr a -> IO ()
foreign import ccall unsafe "stdlib.h &free" finalizerFree :: FinalizerPtr a