module NHC.FFI ( malloc -- :: Storable a => IO (Ptr a) , mallocBytes -- :: Int -> IO (Ptr a) , alloca -- :: Storable a => (Ptr a -> IO b) -> IO b , allocaBytes -- :: Int -> (Ptr a -> IO b) -> IO b , realloc -- :: Storable b => Ptr a -> IO (Ptr b) , reallocBytes -- :: Ptr a -> Int -> IO (Ptr a) , free -- :: Ptr a -> IO () , finalizerFree -- :: FinalizerPtr a ) where import Ptr import ForeignPtr (FinalizerPtr(..)) import Storable import CError import CTypes import CTypesExtra (CSize) import NHC.DErrNo import IO (bracket) import Monad (when) -- allocate space for storable type -- malloc :: Storable a => IO (Ptr a) malloc = doMalloc undefined where doMalloc :: Storable a => a -> IO (Ptr a) doMalloc dummy = mallocBytes (sizeOf dummy) -- allocate given number of bytes of storage -- mallocBytes :: Int -> IO (Ptr a) mallocBytes size = failWhenNULL "malloc" (_malloc (fromIntegral size)) -- temporarily allocate space for a storable type -- -- * the pointer passed as an argument to the function must *not* escape from -- this function; in other words, in `alloca f' the allocated storage must -- not be used after `f' returns -- 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 = allocaBytes (sizeOf dummy) -- temporarily allocate the given number of bytes of storage -- -- * the pointer passed as an argument to the function must *not* escape from -- this function; in other words, in `allocaBytes n f' the allocated storage -- must not be used after `f' returns -- allocaBytes :: Int -> (Ptr a -> IO b) -> IO b allocaBytes size = bracket (mallocBytes size) free -- adjust a malloc'ed storage area to the size of the new type -- realloc :: Storable b => Ptr a -> IO (Ptr b) realloc ptr = doRealloc undefined where doRealloc :: Storable b => b -> IO (Ptr b) doRealloc dummy = failWhenNULL "realloc" (_realloc ptr (fromIntegral (sizeOf dummy))) -- adjust a malloc'ed storage area to the given size -- reallocBytes :: Ptr a -> Int -> IO (Ptr a) reallocBytes ptr size = failWhenNULL "realloc" (_realloc ptr (fromIntegral size)) -- free malloc'ed storage -- free :: Ptr a -> IO () free = _free -- foreign finalizer that performs the free operation -- foreign import ccall "stdlib.h &free" finalizerFree :: FinalizerPtr a --------------------------------------------------------------------------- -- utility functions, not exported failWhenNULL :: String -> IO (Ptr a) -> IO (Ptr a) failWhenNULL nm f = do addr <- f when (addr == nullPtr) (throwIOError (nm++" out of memory") Nothing Nothing (fromEnum ENOMEM)) 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 ()