From 0290e82d74f9aa9f0ae06f96fd71ff93ec91c602 Mon Sep 17 00:00:00 2001 From: ross Date: Mon, 27 Sep 2004 09:04:17 +0000 Subject: [PATCH] [project @ 2004-09-27 09:04:15 by ross] update documentation of memory allocation --- Foreign/C/String.hs | 48 +++++++++++++++++++++------- Foreign/Marshal/Alloc.hs | 80 ++++++++++++++++++++++++++++++++-------------- Foreign/Marshal/Array.hs | 18 +++++++---- Foreign/Marshal/Utils.hs | 19 ++++++++--- 4 files changed, 117 insertions(+), 48 deletions(-) diff --git a/Foreign/C/String.hs b/Foreign/C/String.hs index c624588..b03d32b 100644 --- a/Foreign/C/String.hs +++ b/Foreign/C/String.hs @@ -139,7 +139,9 @@ peekCStringLen = peekCAStringLen -- -- * the Haskell string may /not/ contain any NUL characters -- --- * new storage is allocated for the C string and must be explicitly freed +-- * new storage is allocated for the C string and must be +-- explicitly freed using 'Foreign.Marshal.Alloc.free' or +-- 'Foreign.Marshal.Alloc.finalizerFree'. -- newCString :: String -> IO CString newCString = newCAString @@ -147,7 +149,9 @@ newCString = newCAString -- | Marshal a Haskell string into a C string (ie, character array) with -- explicit length information. -- --- * new storage is allocated for the C string and must be explicitly freed +-- * new storage is allocated for the C string and must be +-- explicitly freed using 'Foreign.Marshal.Alloc.free' or +-- 'Foreign.Marshal.Alloc.finalizerFree'. -- newCStringLen :: String -> IO CStringLen newCStringLen = newCAStringLen @@ -157,7 +161,9 @@ newCStringLen = newCAStringLen -- -- * the Haskell string may /not/ contain any NUL characters -- --- * see the lifetime constraints of 'Foreign.Marshal.Alloc.alloca' +-- * the memory is freed when the subcomputation terminates (either +-- normally or via an exception), so the pointer to the temporary +-- storage must /not/ be used after this. -- withCString :: String -> (CString -> IO a) -> IO a withCString = withCAString @@ -167,7 +173,9 @@ withCString = withCAString -- -- * the Haskell string may /not/ contain any NUL characters -- --- * see the lifetime constraints of 'Foreign.Marshal.Alloc.alloca' +-- * the memory is freed when the subcomputation terminates (either +-- normally or via an exception), so the pointer to the temporary +-- storage must /not/ be used after this. -- withCStringLen :: String -> (CStringLen -> IO a) -> IO a withCStringLen = withCAStringLen @@ -237,7 +245,9 @@ peekCAStringLen (cp, len) -- -- * the Haskell string may /not/ contain any NUL characters -- --- * new storage is allocated for the C string and must be explicitly freed +-- * new storage is allocated for the C string and must be +-- explicitly freed using 'Foreign.Marshal.Alloc.free' or +-- 'Foreign.Marshal.Alloc.finalizerFree'. -- newCAString :: String -> IO CString #ifndef __GLASGOW_HASKELL__ @@ -255,7 +265,9 @@ newCAString str = do -- | Marshal a Haskell string into a C string (ie, character array) with -- explicit length information. -- --- * new storage is allocated for the C string and must be explicitly freed +-- * new storage is allocated for the C string and must be +-- explicitly freed using 'Foreign.Marshal.Alloc.free' or +-- 'Foreign.Marshal.Alloc.finalizerFree'. -- newCAStringLen :: String -> IO CStringLen #ifndef __GLASGOW_HASKELL__ @@ -279,7 +291,9 @@ newCAStringLen str = do -- -- * the Haskell string may /not/ contain any NUL characters -- --- * see the lifetime constraints of 'Foreign.Marshal.Alloc.alloca' +-- * the memory is freed when the subcomputation terminates (either +-- normally or via an exception), so the pointer to the temporary +-- storage must /not/ be used after this. -- withCAString :: String -> (CString -> IO a) -> IO a #ifndef __GLASGOW_HASKELL__ @@ -300,7 +314,9 @@ withCAString str f = -- -- * the Haskell string may /not/ contain any NUL characters -- --- * see the lifetime constraints of 'Foreign.Marshal.Alloc.alloca' +-- * the memory is freed when the subcomputation terminates (either +-- normally or via an exception), so the pointer to the temporary +-- storage must /not/ be used after this. -- withCAStringLen :: String -> (CStringLen -> IO a) -> IO a #ifndef __GLASGOW_HASKELL__ @@ -376,7 +392,9 @@ peekCWStringLen (cp, len) = do -- -- * the Haskell string may /not/ contain any NUL characters -- --- * new storage is allocated for the C string and must be explicitly freed +-- * new storage is allocated for the C wide string and must +-- be explicitly freed using 'Foreign.Marshal.Alloc.free' or +-- 'Foreign.Marshal.Alloc.finalizerFree'. -- newCWString :: String -> IO CWString newCWString = newArray0 wNUL . charsToCWchars @@ -384,7 +402,9 @@ newCWString = newArray0 wNUL . charsToCWchars -- | Marshal a Haskell string into a C wide string (ie, wide character array) -- with explicit length information. -- --- * new storage is allocated for the C string and must be explicitly freed +-- * new storage is allocated for the C wide string and must +-- be explicitly freed using 'Foreign.Marshal.Alloc.free' or +-- 'Foreign.Marshal.Alloc.finalizerFree'. -- newCWStringLen :: String -> IO CWStringLen newCWStringLen str = do @@ -396,7 +416,9 @@ newCWStringLen str = do -- -- * the Haskell string may /not/ contain any NUL characters -- --- * see the lifetime constraints of 'Foreign.Marshal.Alloc.alloca' +-- * the memory is freed when the subcomputation terminates (either +-- normally or via an exception), so the pointer to the temporary +-- storage must /not/ be used after this. -- withCWString :: String -> (CWString -> IO a) -> IO a withCWString = withArray0 wNUL . charsToCWchars @@ -406,7 +428,9 @@ withCWString = withArray0 wNUL . charsToCWchars -- -- * the Haskell string may /not/ contain any NUL characters -- --- * see the lifetime constraints of 'Foreign.Marshal.Alloc.alloca' +-- * the memory is freed when the subcomputation terminates (either +-- normally or via an exception), so the pointer to the temporary +-- storage must /not/ be used after this. -- withCWStringLen :: String -> (CWStringLen -> IO a) -> IO a withCWStringLen str act = withArray (charsToCWchars str) $ act . pairLength str diff --git a/Foreign/Marshal/Alloc.hs b/Foreign/Marshal/Alloc.hs index fb9f8dd..dbd3644 100644 --- a/Foreign/Marshal/Alloc.hs +++ b/Foreign/Marshal/Alloc.hs @@ -14,13 +14,15 @@ ----------------------------------------------------------------------------- module Foreign.Marshal.Alloc ( - -- * Allocation - malloc, -- :: Storable a => IO (Ptr a) - mallocBytes, -- :: Int -> IO (Ptr a) - + -- * 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) @@ -56,9 +58,12 @@ import Hugs.ForeignPtr ( FinalizerPtr ) -- exported functions -- ------------------ --- |Allocate space for storable type. The size of the area allocated --- is determined by the 'sizeOf' method from the instance of --- 'Storable' for the appropriate type. +-- |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 @@ -66,16 +71,22 @@ malloc = doMalloc undefined doMalloc :: Storable a => a -> IO (Ptr a) doMalloc dummy = mallocBytes (sizeOf dummy) --- |Allocate given number of bytes of storage, equivalent to C\'s @malloc()@. +-- |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)) --- |Temporarily allocate space for a storable type. +-- |@'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 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 +-- 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 = doAlloca undefined @@ -83,11 +94,13 @@ alloca = doAlloca undefined doAlloca :: Storable a => a -> (Ptr a -> IO b) -> IO b doAlloca dummy = allocaBytes (sizeOf dummy) --- |Temporarily allocate the given number of bytes of storage. +-- |@'allocaBytes' n f@ executes the computation @f@, passing as argument +-- a pointer to a temporarily allocated block of memory of @n@ 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 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 +-- 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. -- #ifdef __GLASGOW_HASKELL__ allocaBytes :: Int -> (Ptr a -> IO b) -> IO b @@ -105,8 +118,15 @@ allocaBytes :: Int -> (Ptr a -> IO b) -> IO b allocaBytes size = bracket (mallocBytes size) free #endif --- |Adjust a malloc\'ed storage area to the given size of the required type --- (corresponds to C\'s @realloc()@). +-- |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 @@ -117,16 +137,27 @@ realloc = doRealloc undefined in failWhenNULL "realloc" (_realloc ptr size) --- |Adjust a malloc\'ed storage area to the given size (equivalent to --- C\'s @realloc()@). +-- |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 0 = do free ptr; return nullPtr reallocBytes ptr size = failWhenNULL "realloc" (_realloc ptr (fromIntegral size)) --- |Free malloc\'ed storage (equivalent to --- C\'s @free()@) +-- |Free a block of memory that was allocated with 'malloc', +-- 'mallocBytes', 'realloc', 'reallocBytes', 'Foreign.Marshal.Utils.new' +-- or any of the @new@/X/ functions in "Foreign.Marshal.Array" or +-- "Foreign.C.String". -- free :: Ptr a -> IO () free = _free @@ -156,6 +187,7 @@ foreign import ccall unsafe "stdlib.h malloc" _malloc :: CSize -> IO 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 () --- | A pointer to a foreign function equivalent to 'free', which may be used --- as a finalizer for storage allocated with 'malloc' or 'mallocBytes'. +-- | A pointer to a foreign function equivalent to 'free', which may be +-- used as a finalizer (cf 'Foreign.ForeignPtr.ForeignPtr') for storage +-- allocated with 'malloc', 'mallocBytes', 'realloc' or 'reallocBytes'. foreign import ccall unsafe "stdlib.h &free" finalizerFree :: FinalizerPtr a diff --git a/Foreign/Marshal/Array.hs b/Foreign/Marshal/Array.hs index 0799aa7..a28ccc8 100644 --- a/Foreign/Marshal/Array.hs +++ b/Foreign/Marshal/Array.hs @@ -79,7 +79,8 @@ import GHC.Base -- allocation -- ---------- --- |Allocate storage for the given number of elements of a storable type. +-- |Allocate storage for the given number of elements of a storable type +-- (like 'Foreign.Marshal.Alloc.malloc', but for multiple elements). -- mallocArray :: Storable a => Int -> IO (Ptr a) mallocArray = doMalloc undefined @@ -87,14 +88,14 @@ mallocArray = doMalloc undefined doMalloc :: Storable a => a -> Int -> IO (Ptr a) doMalloc dummy size = mallocBytes (size * sizeOf dummy) --- |Like 'mallocArray', but add an extra element to signal the end of the array +-- |Like 'mallocArray', but add an extra position to hold a special +-- termination element. -- mallocArray0 :: Storable a => Int -> IO (Ptr a) mallocArray0 size = mallocArray (size + 1) --- |Temporarily allocate space for the given number of elements. --- --- * see 'Foreign.Marshal.Alloc.alloca' for the storage lifetime constraints +-- |Temporarily allocate space for the given number of elements +-- (like 'Foreign.Marshal.Alloc.alloca', but for multiple elements). -- allocaArray :: Storable a => Int -> (Ptr a -> IO b) -> IO b allocaArray = doAlloca undefined @@ -102,7 +103,8 @@ allocaArray = doAlloca undefined doAlloca :: Storable a => a -> Int -> (Ptr a -> IO b) -> IO b doAlloca dummy size = allocaBytes (size * sizeOf dummy) --- |Like 'allocaArray', but add an extra element to signal the end of the array +-- |Like 'allocaArray', but add an extra position to hold a special +-- termination element. -- allocaArray0 :: Storable a => Int -> (Ptr a -> IO b) -> IO b allocaArray0 size = allocaArray (size + 1) @@ -115,7 +117,7 @@ reallocArray = doRealloc undefined doRealloc :: Storable a => a -> Ptr a -> Int -> IO (Ptr a) doRealloc dummy ptr size = reallocBytes ptr (size * sizeOf dummy) --- |Adjust the size of an array while adding an element for the end marker +-- |Adjust the size of an array including an extra position for the end marker. -- reallocArray0 :: Storable a => Ptr a -> Int -> IO (Ptr a) reallocArray0 ptr size = reallocArray ptr (size + 1) @@ -174,6 +176,7 @@ pokeArray0 marker ptr vals = go vals 0# -- |Write a list of storable elements into a newly allocated, consecutive -- sequence of storable values +-- (like 'Foreign.Marshal.Utils.new', but for multiple elements). -- newArray :: Storable a => [a] -> IO (Ptr a) newArray vals = do @@ -191,6 +194,7 @@ newArray0 marker vals = do return ptr -- |Temporarily store a list of storable values in memory +-- (like 'Foreign.Marshal.Utils.with', but for multiple elements). -- withArray :: Storable a => [a] -> (Ptr a -> IO b) -> IO b withArray vals = withArrayLen vals . const diff --git a/Foreign/Marshal/Utils.hs b/Foreign/Marshal/Utils.hs index 8f11e56..91ae945 100644 --- a/Foreign/Marshal/Utils.hs +++ b/Foreign/Marshal/Utils.hs @@ -70,7 +70,13 @@ import Foreign.C.Types ( CInt(..) ) -- combined allocation and marshalling -- ----------------------------------- --- |Allocate storage for a value and marshal it into this storage +-- |Allocate a block of memory and marshal a value into it +-- (the combination of 'malloc' and 'poke'). +-- The size of the area allocated is determined by the 'Foreign.Storable.sizeOf' +-- method from the instance of 'Storable' for the appropriate type. +-- +-- The memory may be deallocated using 'Foreign.Marshal.Alloc.free' or +-- 'Foreign.Marshal.Alloc.finalizerFree' when no longer required. -- new :: Storable a => a -> IO (Ptr a) new val = @@ -79,9 +85,12 @@ new val = poke ptr val return ptr --- |Allocate temporary storage for a value and marshal it into this storage +-- |@'with' val f@ executes the computation @f@, passing as argument +-- a pointer to a temporarily allocated block of memory into which +-- 'val' has been marshalled (the combination of 'alloca' and 'poke'). -- --- * see the life time constraints imposed by 'alloca' +-- 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. -- with :: Storable a => a -> (Ptr a -> IO b) -> IO b with val f = @@ -123,8 +132,8 @@ maybeNew :: ( a -> IO (Ptr a)) -> (Maybe a -> IO (Ptr a)) maybeNew = maybe (return nullPtr) --- |Converts a @withXXX@ combinator into one marshalling a value wrapped into a --- 'Maybe' +-- |Converts a @withXXX@ combinator into one marshalling a value wrapped +-- into a 'Maybe', using 'nullPtr' to represent 'Nothing'. -- maybeWith :: ( a -> (Ptr b -> IO c) -> IO c) -> (Maybe a -> (Ptr b -> IO c) -> IO c) -- 1.7.10.4