[project @ 2002-04-26 13:34:05 by simonmar]
[haskell-directory.git] / Foreign / Marshal / Array.hs
1 {-# OPTIONS -fno-implicit-prelude #-}
2 -----------------------------------------------------------------------------
3 -- |
4 -- Module      :  Foreign.Marshal.Array
5 -- Copyright   :  (c) The FFI task force 2001
6 -- License     :  BSD-style (see the file libraries/core/LICENSE)
7 -- 
8 -- Maintainer  :  ffi@haskell.org
9 -- Stability   :  provisional
10 -- Portability :  portable
11 --
12 -- Marshalling support: routines allocating, storing, and retrieving Haskell
13 -- lists that are represented as arrays in the foreign language
14 --
15 -----------------------------------------------------------------------------
16
17 module Foreign.Marshal.Array (
18
19   -- allocation
20   --
21   mallocArray,    -- :: Storable a => Int -> IO (Ptr a)
22   mallocArray0,   -- :: Storable a => Int -> IO (Ptr a)
23
24   allocaArray,    -- :: Storable a => Int -> (Ptr a -> IO b) -> IO b
25   allocaArray0,   -- :: Storable a => Int -> (Ptr a -> IO b) -> IO b
26
27   reallocArray,   -- :: Storable a => Ptr a -> Int -> IO (Ptr a)
28   reallocArray0,  -- :: Storable a => Ptr a -> Int -> IO (Ptr a)
29
30   -- marshalling
31   --
32   peekArray,      -- :: Storable a =>         Int -> Ptr a -> IO [a]
33   peekArray0,     -- :: (Storable a, Eq a) => a   -> Ptr a -> IO [a]
34
35   pokeArray,      -- :: Storable a =>      Ptr a -> [a] -> IO ()
36   pokeArray0,     -- :: Storable a => a -> Ptr a -> [a] -> IO ()
37
38   -- combined allocation and marshalling
39   --
40   newArray,       -- :: Storable a =>      [a] -> IO (Ptr a)
41   newArray0,      -- :: Storable a => a -> [a] -> IO (Ptr a)
42
43   withArray,      -- :: Storable a =>      [a] -> (Ptr a -> IO b) -> IO b
44   withArray0,     -- :: Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b
45
46   -- copying (argument order: destination, source)
47   --
48   copyArray,      -- :: Storable a => Ptr a -> Ptr a -> Int -> IO ()
49   moveArray,      -- :: Storable a => Ptr a -> Ptr a -> Int -> IO ()
50
51   -- finding the length
52   --
53   lengthArray0,   -- :: (Storable a, Eq a) => a -> Ptr a -> IO Int
54
55   -- indexing
56   --
57   advancePtr,     -- :: Storable a => Ptr a -> Int -> Ptr a
58 ) where
59
60 import Control.Monad
61
62 #ifdef __GLASGOW_HASKELL__
63 import Foreign.Ptr              (Ptr, plusPtr)
64 import GHC.Storable     (Storable(sizeOf,peekElemOff,pokeElemOff))
65 import Foreign.Marshal.Alloc (mallocBytes, allocaBytes, reallocBytes)
66 import Foreign.Marshal.Utils (copyBytes, moveBytes)
67 import GHC.IOBase
68 import GHC.Num
69 import GHC.List
70 import GHC.Err
71 import GHC.Base
72 #endif
73
74 -- allocation
75 -- ----------
76
77 -- allocate storage for the given number of elements of a storable type
78 --
79 mallocArray :: Storable a => Int -> IO (Ptr a)
80 mallocArray  = doMalloc undefined
81   where
82     doMalloc            :: Storable a => a -> Int -> IO (Ptr a)
83     doMalloc dummy size  = mallocBytes (size * sizeOf dummy)
84
85 -- like `mallocArray', but add an extra element to signal the end of the array
86 --
87 mallocArray0      :: Storable a => Int -> IO (Ptr a)
88 mallocArray0 size  = mallocArray (size + 1)
89
90 -- temporarily allocate space for the given number of elements
91 --
92 -- * see `MarshalAlloc.alloca' for the storage lifetime constraints
93 --
94 allocaArray :: Storable a => Int -> (Ptr a -> IO b) -> IO b
95 allocaArray  = doAlloca undefined
96   where
97     doAlloca            :: Storable a => a -> Int -> (Ptr a -> IO b) -> IO b
98     doAlloca dummy size  = allocaBytes (size * sizeOf dummy)
99
100 -- like `allocaArray', but add an extra element to signal the end of the array
101 --
102 allocaArray0      :: Storable a => Int -> (Ptr a -> IO b) -> IO b
103 allocaArray0 size  = allocaArray (size + 1)
104
105 -- adjust the size of an array
106 --
107 reallocArray :: Storable a => Ptr a -> Int -> IO (Ptr a)
108 reallocArray  = doRealloc undefined
109   where
110     doRealloc                :: Storable a => a -> Ptr a -> Int -> IO (Ptr a)
111     doRealloc dummy ptr size  = reallocBytes ptr (size * sizeOf dummy)
112
113 -- adjust the size of an array while adding an element for the end marker
114 --
115 reallocArray0          :: Storable a => Ptr a -> Int -> IO (Ptr a)
116 reallocArray0 ptr size  = reallocArray ptr (size + 1)
117
118
119 -- marshalling
120 -- -----------
121
122 -- convert an array of given length into a Haskell list.  This version
123 -- traverses the array backwards using an accumulating parameter,
124 -- which uses constant stack space.  The previous version using mapM
125 -- needed linear stack space.
126 --
127 peekArray          :: Storable a => Int -> Ptr a -> IO [a]
128 peekArray size ptr | size <= 0 = return []
129                  | otherwise = f (size-1) []
130   where
131     f 0 acc = do e <- peekElemOff ptr 0; return (e:acc)
132     f n acc = do e <- peekElemOff ptr n; f (n-1) (e:acc)
133   
134 -- convert an array terminated by the given end marker into a Haskell list
135 --
136 peekArray0            :: (Storable a, Eq a) => a -> Ptr a -> IO [a]
137 peekArray0 marker ptr  = loop 0
138   where
139     loop i = do
140         val <- peekElemOff ptr i
141         if val == marker then return [] else do
142             rest <- loop (i+1)
143             return (val:rest)
144
145 -- write the list elements consecutive into memory
146 --
147 pokeArray          :: Storable a => Ptr a -> [a] -> IO ()
148 pokeArray ptr vals  = zipWithM_ (pokeElemOff ptr) [0..] vals
149
150 -- write the list elements consecutive into memory and terminate them with the
151 -- given marker element
152 --
153 pokeArray0                 :: Storable a => a -> Ptr a -> [a] -> IO ()
154 pokeArray0 marker ptr vals  = do
155   pokeArray ptr vals
156   pokeElemOff ptr (length vals) marker
157
158
159 -- combined allocation and marshalling
160 -- -----------------------------------
161
162 -- write a list of storable elements into a newly allocated, consecutive
163 -- sequence of storable values
164 --
165 newArray      :: Storable a => [a] -> IO (Ptr a)
166 newArray vals  = do
167   ptr <- mallocArray (length vals)
168   pokeArray ptr vals
169   return ptr
170
171 -- write a list of storable elements into a newly allocated, consecutive
172 -- sequence of storable values, where the end is fixed by the given end marker
173 --
174 newArray0             :: Storable a => a -> [a] -> IO (Ptr a)
175 newArray0 marker vals  = do
176   ptr <- mallocArray0 (length vals)
177   pokeArray0 marker ptr vals
178   return ptr
179
180 -- temporarily store a list of storable values in memory
181 --
182 withArray        :: Storable a => [a] -> (Ptr a -> IO b) -> IO b
183 withArray vals f  =
184   allocaArray len $ \ptr -> do
185       pokeArray ptr vals
186       res <- f ptr
187       return res
188   where
189     len = length vals
190
191 -- like `withArray', but a terminator indicates where the array ends
192 --
193 withArray0               :: Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b
194 withArray0 marker vals f  =
195   allocaArray0 len $ \ptr -> do
196       pokeArray0 marker ptr vals
197       res <- f ptr
198       return res
199   where
200     len = length vals
201
202
203 -- copying (argument order: destination, source)
204 -- -------
205
206 -- copy the given number of elements from the second array (source) into the
207 -- first array (destination); the copied areas may *not* overlap
208 --
209 copyArray :: Storable a => Ptr a -> Ptr a -> Int -> IO ()
210 copyArray  = doCopy undefined
211   where
212     doCopy                     :: Storable a => a -> Ptr a -> Ptr a -> Int -> IO ()
213     doCopy dummy dest src size  = copyBytes dest src (size * sizeOf dummy)
214
215 -- copy the given number of elements from the second array (source) into the
216 -- first array (destination); the copied areas *may* overlap
217 --
218 moveArray :: Storable a => Ptr a -> Ptr a -> Int -> IO ()
219 moveArray  = doMove undefined
220   where
221     doMove                     :: Storable a => a -> Ptr a -> Ptr a -> Int -> IO ()
222     doMove dummy dest src size  = moveBytes dest src (size * sizeOf dummy)
223
224
225 -- finding the length
226 -- ------------------
227
228 -- return the number of elements in an array, excluding the terminator
229 --
230 lengthArray0            :: (Storable a, Eq a) => a -> Ptr a -> IO Int
231 lengthArray0 marker ptr  = loop 0
232   where
233     loop i = do
234         val <- peekElemOff ptr i
235         if val == marker then return i else loop (i+1)
236
237
238 -- indexing
239 -- --------
240
241 -- advance a pointer into an array by the given number of elements
242 --
243 advancePtr :: Storable a => Ptr a -> Int -> Ptr a
244 advancePtr  = doAdvance undefined
245   where
246     doAdvance             :: Storable a => a -> Ptr a -> Int -> Ptr a
247     doAdvance dummy ptr i  = ptr `plusPtr` (i * sizeOf dummy)