lhc-0.6.20081210.1: lib/base/src/Foreign/Marshal/Alloc.hs
{-# OPTIONS_LHC -N -fffi #-}
module Foreign.Marshal.Alloc (
-- * Memory allocation
-- ** Local allocation
alloca, -- :: Storable a => (Ptr a -> IO b) -> IO b
allocaBytes, -- :: Int -> (Ptr a -> IO b) -> IO b
-- ** Dynamic allocation
malloc, -- :: Storable a => IO (Ptr a)
mallocBytes, -- :: Int -> IO (Ptr a)
realloc, -- :: Storable b => Ptr a -> IO (Ptr b)
reallocBytes, -- :: Ptr a -> Int -> IO (Ptr a)
free, -- :: Ptr a -> IO ()
finalizerFree -- :: FinalizerPtr a
) where
import Foreign.Ptr
import Foreign.Storable
import Prelude.IO
import Foreign.C.Types
import Foreign.Marshal.Utils
import Prelude.IOError
import Lhc.Prim
import Lhc.Basics
import Lhc.Monad
import Lhc.Order
import Lhc.IO
import Lhc.Int(unboxInt)
import Lhc.Addr
import Lhc.Num
import qualified Lhc.Options as JO
-- TODO handle exceptions
allocaBytes' :: Int -> (Ptr a -> IO b) -> IO b
allocaBytes' b f = do
p <- mallocBytes b
r <- f p
free p
return r
allocaBytes :: Int -> (Ptr a -> IO b) -> IO b
allocaBytes num fn = etaIO $ case JO.target of
JO.GhcHs -> case unboxInt num of n -> alloca__ n (\addr -> fn (boxAddr addr))
_ -> allocaBytes' num fn
foreign import primitive alloca__ :: Int__ -> (Addr__ -> IO b) -> IO b
foreign import primitive "box" boxAddr :: Addr__ -> Ptr a
-- exported functions
-- ------------------
-- |Allocate a block of memory that is sufficient to hold values of type
-- @a@. The size of the area allocated is determined by the 'sizeOf'
-- method from the instance of 'Storable' for the appropriate type.
--
-- The memory may be deallocated using 'free' or 'finalizerFree' when
-- no longer required.
--
malloc :: Storable a => IO (Ptr a)
malloc = doMalloc undefined
doMalloc :: Storable b => b -> IO (Ptr b)
doMalloc dummy = mallocBytes (sizeOf dummy)
-- |@'alloca' f@ executes the computation @f@, passing as argument
-- a pointer to a temporarily allocated block of memory sufficient to
-- hold values of type @a@.
--
-- The memory is freed when @f@ terminates (either normally or via an
-- exception), so the pointer passed to @f@ must /not/ be used after this.
--
alloca :: Storable a => (Ptr a -> IO b) -> IO b
alloca fn = etaIO $ doAlloca undefined fn where
doAlloca :: Storable a' => a' -> (Ptr a' -> IO b') -> IO b'
doAlloca dummy fn = allocaBytes (sizeOf dummy) fn
failWhenNULL :: String -> IO (Ptr a) -> IO (Ptr a)
failWhenNULL name f = do
addr <- f
if addr == nullPtr
then ioError (userError (name++": out of memory"))
else return addr
-- |Allocate a block of memory of the given number of bytes.
-- The block of memory is sufficiently aligned for any of the basic
-- foreign types that fits into a memory block of the allocated size.
--
-- The memory may be deallocated using 'free' or 'finalizerFree' when
-- no longer required.
--
mallocBytes :: Int -> IO (Ptr a)
mallocBytes size = failWhenNULL "malloc" (_malloc (fromIntegral size))
-- |Resize a memory area that was allocated with 'malloc' or 'mallocBytes'
-- to the size needed to store values of type @b@. The returned pointer
-- may refer to an entirely different memory area, but will be suitably
-- aligned to hold values of type @b@. The contents of the referenced
-- memory area will be the same as of the original pointer up to the
-- minimum of the original size and the size of values of type @b@.
--
-- If the argument to 'realloc' is 'nullPtr', 'realloc' behaves like
-- 'malloc'.
--
realloc :: Storable b => Ptr a -> IO (Ptr b)
realloc = doRealloc undefined
doRealloc :: Storable b' => b' -> Ptr a' -> IO (Ptr b')
doRealloc dummy ptr = let
size = fromIntegral (sizeOf dummy)
in
failWhenNULL "realloc" (_realloc ptr size)
-- |Resize a memory area that was allocated with 'malloc' or 'mallocBytes'
-- to the given size. The returned pointer may refer to an entirely
-- different memory area, but will be sufficiently aligned for any of the
-- basic foreign types that fits into a memory block of the given size.
-- The contents of the referenced memory area will be the same as of
-- the original pointer up to the minimum of the original size and the
-- given size.
--
-- If the pointer argument to 'reallocBytes' is 'nullPtr', 'reallocBytes'
-- behaves like 'malloc'. If the requested size is 0, 'reallocBytes'
-- behaves like 'free'.
--
reallocBytes :: Ptr a -> Int -> IO (Ptr a)
reallocBytes ptr i | ptr `seq` i `seq` False = undefined
reallocBytes ptr 0 = do free ptr; return nullPtr
reallocBytes ptr size =
failWhenNULL "realloc" (_realloc ptr (fromIntegral size))
foreign import ccall "stdlib.h malloc" _malloc :: CSize -> IO (Ptr a)
foreign import ccall "stdlib.h free" free :: Ptr a -> IO ()
foreign import ccall "stdlib.h realloc" _realloc :: Ptr a -> CSize -> IO (Ptr b)