1 {-# LANGUAGE CPP, NoImplicitPrelude, MagicHash #-}
3 -----------------------------------------------------------------------------
5 -- Module : Foreign.Marshal.Array
6 -- Copyright : (c) The FFI task force 2001
7 -- License : BSD-style (see the file libraries/base/LICENSE)
9 -- Maintainer : ffi@haskell.org
10 -- Stability : provisional
11 -- Portability : portable
13 -- Marshalling support: routines allocating, storing, and retrieving Haskell
14 -- lists that are represented as arrays in the foreign language
16 -----------------------------------------------------------------------------
18 module Foreign.Marshal.Array (
19 -- * Marshalling arrays
23 mallocArray, -- :: Storable a => Int -> IO (Ptr a)
24 mallocArray0, -- :: Storable a => Int -> IO (Ptr a)
26 allocaArray, -- :: Storable a => Int -> (Ptr a -> IO b) -> IO b
27 allocaArray0, -- :: Storable a => Int -> (Ptr a -> IO b) -> IO b
29 reallocArray, -- :: Storable a => Ptr a -> Int -> IO (Ptr a)
30 reallocArray0, -- :: Storable a => Ptr a -> Int -> IO (Ptr a)
34 peekArray, -- :: Storable a => Int -> Ptr a -> IO [a]
35 peekArray0, -- :: (Storable a, Eq a) => a -> Ptr a -> IO [a]
37 pokeArray, -- :: Storable a => Ptr a -> [a] -> IO ()
38 pokeArray0, -- :: Storable a => a -> Ptr a -> [a] -> IO ()
40 -- ** Combined allocation and marshalling
42 newArray, -- :: Storable a => [a] -> IO (Ptr a)
43 newArray0, -- :: Storable a => a -> [a] -> IO (Ptr a)
45 withArray, -- :: Storable a => [a] -> (Ptr a -> IO b) -> IO b
46 withArray0, -- :: Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b
48 withArrayLen, -- :: Storable a => [a] -> (Int -> Ptr a -> IO b) -> IO b
49 withArrayLen0, -- :: Storable a => a -> [a] -> (Int -> Ptr a -> IO b) -> IO b
53 -- | (argument order: destination, source)
54 copyArray, -- :: Storable a => Ptr a -> Ptr a -> Int -> IO ()
55 moveArray, -- :: Storable a => Ptr a -> Ptr a -> Int -> IO ()
57 -- ** Finding the length
59 lengthArray0, -- :: (Storable a, Eq a) => a -> Ptr a -> IO Int
63 advancePtr, -- :: Storable a => Ptr a -> Int -> Ptr a
66 import Foreign.Ptr (Ptr, plusPtr)
67 import Foreign.Storable (Storable(alignment,sizeOf,peekElemOff,pokeElemOff))
68 import Foreign.Marshal.Alloc (mallocBytes, allocaBytesAligned, reallocBytes)
69 import Foreign.Marshal.Utils (copyBytes, moveBytes)
71 #ifdef __GLASGOW_HASKELL__
77 import Control.Monad (zipWithM_)
83 -- |Allocate storage for the given number of elements of a storable type
84 -- (like 'Foreign.Marshal.Alloc.malloc', but for multiple elements).
86 mallocArray :: Storable a => Int -> IO (Ptr a)
87 mallocArray = doMalloc undefined
89 doMalloc :: Storable a' => a' -> Int -> IO (Ptr a')
90 doMalloc dummy size = mallocBytes (size * sizeOf dummy)
92 -- |Like 'mallocArray', but add an extra position to hold a special
93 -- termination element.
95 mallocArray0 :: Storable a => Int -> IO (Ptr a)
96 mallocArray0 size = mallocArray (size + 1)
98 -- |Temporarily allocate space for the given number of elements
99 -- (like 'Foreign.Marshal.Alloc.alloca', but for multiple elements).
101 allocaArray :: Storable a => Int -> (Ptr a -> IO b) -> IO b
102 allocaArray = doAlloca undefined
104 doAlloca :: Storable a' => a' -> Int -> (Ptr a' -> IO b') -> IO b'
105 doAlloca dummy size = allocaBytesAligned (size * sizeOf dummy)
108 -- |Like 'allocaArray', but add an extra position to hold a special
109 -- termination element.
111 allocaArray0 :: Storable a => Int -> (Ptr a -> IO b) -> IO b
112 allocaArray0 size = allocaArray (size + 1)
113 {-# INLINE allocaArray0 #-}
114 -- needed to get allocaArray to inline into withCString, for unknown
115 -- reasons --SDM 23/4/2010, see #4004 for benchmark
117 -- |Adjust the size of an array
119 reallocArray :: Storable a => Ptr a -> Int -> IO (Ptr a)
120 reallocArray = doRealloc undefined
122 doRealloc :: Storable a' => a' -> Ptr a' -> Int -> IO (Ptr a')
123 doRealloc dummy ptr size = reallocBytes ptr (size * sizeOf dummy)
125 -- |Adjust the size of an array including an extra position for the end marker.
127 reallocArray0 :: Storable a => Ptr a -> Int -> IO (Ptr a)
128 reallocArray0 ptr size = reallocArray ptr (size + 1)
134 -- |Convert an array of given length into a Haskell list. The implementation
135 -- is tail-recursive and so uses constant stack space.
137 peekArray :: Storable a => Int -> Ptr a -> IO [a]
138 peekArray size ptr | size <= 0 = return []
139 | otherwise = f (size-1) []
141 f 0 acc = do e <- peekElemOff ptr 0; return (e:acc)
142 f n acc = do e <- peekElemOff ptr n; f (n-1) (e:acc)
144 -- |Convert an array terminated by the given end marker into a Haskell list
146 peekArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO [a]
147 peekArray0 marker ptr = do
148 size <- lengthArray0 marker ptr
151 -- |Write the list elements consecutive into memory
153 pokeArray :: Storable a => Ptr a -> [a] -> IO ()
154 #ifndef __GLASGOW_HASKELL__
155 pokeArray ptr vals = zipWithM_ (pokeElemOff ptr) [0..] vals
157 pokeArray ptr vals0 = go vals0 0#
158 where go [] _ = return ()
159 go (val:vals) n# = do pokeElemOff ptr (I# n#) val; go vals (n# +# 1#)
162 -- |Write the list elements consecutive into memory and terminate them with the
163 -- given marker element
165 pokeArray0 :: Storable a => a -> Ptr a -> [a] -> IO ()
166 #ifndef __GLASGOW_HASKELL__
167 pokeArray0 marker ptr vals = do
169 pokeElemOff ptr (length vals) marker
171 pokeArray0 marker ptr vals0 = go vals0 0#
172 where go [] n# = pokeElemOff ptr (I# n#) marker
173 go (val:vals) n# = do pokeElemOff ptr (I# n#) val; go vals (n# +# 1#)
177 -- combined allocation and marshalling
178 -- -----------------------------------
180 -- |Write a list of storable elements into a newly allocated, consecutive
181 -- sequence of storable values
182 -- (like 'Foreign.Marshal.Utils.new', but for multiple elements).
184 newArray :: Storable a => [a] -> IO (Ptr a)
186 ptr <- mallocArray (length vals)
190 -- |Write a list of storable elements into a newly allocated, consecutive
191 -- sequence of storable values, where the end is fixed by the given end marker
193 newArray0 :: Storable a => a -> [a] -> IO (Ptr a)
194 newArray0 marker vals = do
195 ptr <- mallocArray0 (length vals)
196 pokeArray0 marker ptr vals
199 -- |Temporarily store a list of storable values in memory
200 -- (like 'Foreign.Marshal.Utils.with', but for multiple elements).
202 withArray :: Storable a => [a] -> (Ptr a -> IO b) -> IO b
203 withArray vals = withArrayLen vals . const
205 -- |Like 'withArray', but the action gets the number of values
206 -- as an additional parameter
208 withArrayLen :: Storable a => [a] -> (Int -> Ptr a -> IO b) -> IO b
209 withArrayLen vals f =
210 allocaArray len $ \ptr -> do
217 -- |Like 'withArray', but a terminator indicates where the array ends
219 withArray0 :: Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b
220 withArray0 marker vals = withArrayLen0 marker vals . const
222 -- |Like 'withArrayLen', but a terminator indicates where the array ends
224 withArrayLen0 :: Storable a => a -> [a] -> (Int -> Ptr a -> IO b) -> IO b
225 withArrayLen0 marker vals f =
226 allocaArray0 len $ \ptr -> do
227 pokeArray0 marker ptr vals
234 -- copying (argument order: destination, source)
237 -- |Copy the given number of elements from the second array (source) into the
238 -- first array (destination); the copied areas may /not/ overlap
240 copyArray :: Storable a => Ptr a -> Ptr a -> Int -> IO ()
241 copyArray = doCopy undefined
243 doCopy :: Storable a' => a' -> Ptr a' -> Ptr a' -> Int -> IO ()
244 doCopy dummy dest src size = copyBytes dest src (size * sizeOf dummy)
246 -- |Copy the given number of elements from the second array (source) into the
247 -- first array (destination); the copied areas /may/ overlap
249 moveArray :: Storable a => Ptr a -> Ptr a -> Int -> IO ()
250 moveArray = doMove undefined
252 doMove :: Storable a' => a' -> Ptr a' -> Ptr a' -> Int -> IO ()
253 doMove dummy dest src size = moveBytes dest src (size * sizeOf dummy)
256 -- finding the length
257 -- ------------------
259 -- |Return the number of elements in an array, excluding the terminator
261 lengthArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO Int
262 lengthArray0 marker ptr = loop 0
265 val <- peekElemOff ptr i
266 if val == marker then return i else loop (i+1)
272 -- |Advance a pointer into an array by the given number of elements
274 advancePtr :: Storable a => Ptr a -> Int -> Ptr a
275 advancePtr = doAdvance undefined
277 doAdvance :: Storable a' => a' -> Ptr a' -> Int -> Ptr a'
278 doAdvance dummy ptr i = ptr `plusPtr` (i * sizeOf dummy)