[project @ 2002-09-20 13:15:07 by ross]
[ghc-base.git] / Data / Array / IO.hs
1 {-# OPTIONS -#include "HsBase.h" #-}
2 -----------------------------------------------------------------------------
3 -- |
4 -- Module      :  Data.Array.IO
5 -- Copyright   :  (c) The University of Glasgow 2001
6 -- License     :  BSD-style (see the file libraries/base/LICENSE)
7 -- 
8 -- Maintainer  :  libraries@haskell.org
9 -- Stability   :  experimental
10 -- Portability :  non-portable
11 --
12 -- Mutable boxed and unboxed arrays in the IO monad.
13 --
14 -----------------------------------------------------------------------------
15
16 module Data.Array.IO (
17    -- * @IO@ arrays with boxed elements
18    IOArray,             -- instance of: Eq, Typeable
19
20 #ifdef __GLASGOW_HASKELL__
21    -- * @IO@ arrays with unboxed elements
22    IOUArray,            -- instance of: Eq, Typeable
23    castIOUArray,        -- :: IOUArray i a -> IO (IOUArray i b)
24 #endif
25
26    -- * Overloaded mutable array interface
27    module Data.Array.MArray,
28
29 #ifdef __GLASGOW_HASKELL__
30    -- * Doing I\/O with @IOUArray@s
31    hGetArray,           -- :: Handle -> IOUArray Int Word8 -> Int -> IO Int
32    hPutArray,           -- :: Handle -> IOUArray Int Word8 -> Int -> IO ()
33 #endif
34  ) where
35
36 import Prelude
37
38 import Data.Array               ( Array )
39 import Data.Array.MArray
40 import Data.Int
41 import Data.Word
42 import Data.Dynamic
43
44 #ifdef __HUGS__
45 import Hugs.IOArray
46 #endif
47
48 #ifdef __GLASGOW_HASKELL__
49 import Foreign.C
50 import Foreign.Ptr              ( Ptr, FunPtr )
51 import Foreign.StablePtr        ( StablePtr )
52
53 import Data.Array.Base
54 import GHC.Arr          ( STArray, freezeSTArray, unsafeFreezeSTArray,
55                           thawSTArray, unsafeThawSTArray )
56
57 import GHC.ST           ( ST(..) )
58
59 import GHC.IOBase
60 import GHC.Handle
61 import GHC.Conc
62
63 import GHC.Base
64 #endif /* __GLASGOW_HASKELL__ */
65
66 #ifdef __HUGS__
67 instance HasBounds IOArray where
68     bounds = boundsIOArray
69
70 instance MArray IOArray e IO where
71     newArray    = newIOArray
72     unsafeRead  = unsafeReadIOArray
73     unsafeWrite = unsafeWriteIOArray
74 #endif /* __HUGS__ */
75
76 iOArrayTc :: TyCon
77 iOArrayTc = mkTyCon "IOArray"
78
79 instance (Typeable a, Typeable b) => Typeable (IOArray a b) where
80   typeOf a = mkAppTy iOArrayTc [typeOf ((undefined :: IOArray a b -> a) a),
81                                 typeOf ((undefined :: IOArray a b -> b) a)]
82
83 #ifdef __GLASGOW_HASKELL__
84 -- GHC only to the end of file
85
86 -----------------------------------------------------------------------------
87 -- | Mutable, boxed, non-strict arrays in the 'IO' monad.  The type
88 -- arguments are as follows:
89 --
90 --  * @i@: the index type of the array (should be an instance of @Ix@)
91 --
92 --  * @e@: the element type of the array.
93 --
94 newtype IOArray i e = IOArray (STArray RealWorld i e) deriving Eq
95
96 instance HasBounds IOArray where
97     {-# INLINE bounds #-}
98     bounds (IOArray marr) = bounds marr
99
100 instance MArray IOArray e IO where
101     {-# INLINE newArray #-}
102     newArray lu init = stToIO $ do
103         marr <- newArray lu init; return (IOArray marr)
104     {-# INLINE newArray_ #-}
105     newArray_ lu = stToIO $ do
106         marr <- newArray_ lu; return (IOArray marr)
107     {-# INLINE unsafeRead #-}
108     unsafeRead (IOArray marr) i = stToIO (unsafeRead marr i)
109     {-# INLINE unsafeWrite #-}
110     unsafeWrite (IOArray marr) i e = stToIO (unsafeWrite marr i e)
111
112 -----------------------------------------------------------------------------
113 -- Flat unboxed mutable arrays (IO monad)
114
115 -- | Mutable, unboxed, strict arrays in the 'IO' monad.  The type
116 -- arguments are as follows:
117 --
118 --  * @i@: the index type of the array (should be an instance of @Ix@)
119 --
120 --  * @e@: the element type of the array.  Only certain element types
121 --    are supported: see 'MArray' for a list of instances.
122 --
123 newtype IOUArray i e = IOUArray (STUArray RealWorld i e) deriving Eq
124
125 iOUArrayTc :: TyCon
126 iOUArrayTc = mkTyCon "IOUArray"
127
128 instance (Typeable a, Typeable b) => Typeable (IOUArray a b) where
129   typeOf a = mkAppTy iOUArrayTc [typeOf ((undefined :: IOUArray a b -> a) a),
130                                  typeOf ((undefined :: IOUArray a b -> b) a)]
131
132 instance HasBounds IOUArray where
133     {-# INLINE bounds #-}
134     bounds (IOUArray marr) = bounds marr
135
136 instance MArray IOUArray Bool IO where
137     {-# INLINE newArray #-}
138     newArray lu init = stToIO $ do
139         marr <- newArray lu init; return (IOUArray marr)
140     {-# INLINE newArray_ #-}
141     newArray_ lu = stToIO $ do
142         marr <- newArray_ lu; return (IOUArray marr)
143     {-# INLINE unsafeRead #-}
144     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
145     {-# INLINE unsafeWrite #-}
146     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
147
148 instance MArray IOUArray Char IO where
149     {-# INLINE newArray #-}
150     newArray lu init = stToIO $ do
151         marr <- newArray lu init; return (IOUArray marr)
152     {-# INLINE newArray_ #-}
153     newArray_ lu = stToIO $ do
154         marr <- newArray_ lu; return (IOUArray marr)
155     {-# INLINE unsafeRead #-}
156     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
157     {-# INLINE unsafeWrite #-}
158     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
159
160 instance MArray IOUArray Int IO where
161     {-# INLINE newArray #-}
162     newArray lu init = stToIO $ do
163         marr <- newArray lu init; return (IOUArray marr)
164     {-# INLINE newArray_ #-}
165     newArray_ lu = stToIO $ do
166         marr <- newArray_ lu; return (IOUArray marr)
167     {-# INLINE unsafeRead #-}
168     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
169     {-# INLINE unsafeWrite #-}
170     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
171
172 instance MArray IOUArray Word IO where
173     {-# INLINE newArray #-}
174     newArray lu init = stToIO $ do
175         marr <- newArray lu init; return (IOUArray marr)
176     {-# INLINE newArray_ #-}
177     newArray_ lu = stToIO $ do
178         marr <- newArray_ lu; return (IOUArray marr)
179     {-# INLINE unsafeRead #-}
180     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
181     {-# INLINE unsafeWrite #-}
182     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
183
184 instance MArray IOUArray (Ptr a) IO where
185     {-# INLINE newArray #-}
186     newArray lu init = stToIO $ do
187         marr <- newArray lu init; return (IOUArray marr)
188     {-# INLINE newArray_ #-}
189     newArray_ lu = stToIO $ do
190         marr <- newArray_ lu; return (IOUArray marr)
191     {-# INLINE unsafeRead #-}
192     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
193     {-# INLINE unsafeWrite #-}
194     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
195
196 instance MArray IOUArray (FunPtr a) IO where
197     {-# INLINE newArray #-}
198     newArray lu init = stToIO $ do
199         marr <- newArray lu init; return (IOUArray marr)
200     {-# INLINE newArray_ #-}
201     newArray_ lu = stToIO $ do
202         marr <- newArray_ lu; return (IOUArray marr)
203     {-# INLINE unsafeRead #-}
204     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
205     {-# INLINE unsafeWrite #-}
206     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
207
208 instance MArray IOUArray Float IO where
209     {-# INLINE newArray #-}
210     newArray lu init = stToIO $ do
211         marr <- newArray lu init; return (IOUArray marr)
212     {-# INLINE newArray_ #-}
213     newArray_ lu = stToIO $ do
214         marr <- newArray_ lu; return (IOUArray marr)
215     {-# INLINE unsafeRead #-}
216     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
217     {-# INLINE unsafeWrite #-}
218     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
219
220 instance MArray IOUArray Double IO where
221     {-# INLINE newArray #-}
222     newArray lu init = stToIO $ do
223         marr <- newArray lu init; return (IOUArray marr)
224     {-# INLINE newArray_ #-}
225     newArray_ lu = stToIO $ do
226         marr <- newArray_ lu; return (IOUArray marr)
227     {-# INLINE unsafeRead #-}
228     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
229     {-# INLINE unsafeWrite #-}
230     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
231
232 instance MArray IOUArray (StablePtr a) IO where
233     {-# INLINE newArray #-}
234     newArray lu init = stToIO $ do
235         marr <- newArray lu init; return (IOUArray marr)
236     {-# INLINE newArray_ #-}
237     newArray_ lu = stToIO $ do
238         marr <- newArray_ lu; return (IOUArray marr)
239     {-# INLINE unsafeRead #-}
240     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
241     {-# INLINE unsafeWrite #-}
242     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
243
244 instance MArray IOUArray Int8 IO where
245     {-# INLINE newArray #-}
246     newArray lu init = stToIO $ do
247         marr <- newArray lu init; return (IOUArray marr)
248     {-# INLINE newArray_ #-}
249     newArray_ lu = stToIO $ do
250         marr <- newArray_ lu; return (IOUArray marr)
251     {-# INLINE unsafeRead #-}
252     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
253     {-# INLINE unsafeWrite #-}
254     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
255
256 instance MArray IOUArray Int16 IO where
257     {-# INLINE newArray #-}
258     newArray lu init = stToIO $ do
259         marr <- newArray lu init; return (IOUArray marr)
260     {-# INLINE newArray_ #-}
261     newArray_ lu = stToIO $ do
262         marr <- newArray_ lu; return (IOUArray marr)
263     {-# INLINE unsafeRead #-}
264     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
265     {-# INLINE unsafeWrite #-}
266     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
267
268 instance MArray IOUArray Int32 IO where
269     {-# INLINE newArray #-}
270     newArray lu init = stToIO $ do
271         marr <- newArray lu init; return (IOUArray marr)
272     {-# INLINE newArray_ #-}
273     newArray_ lu = stToIO $ do
274         marr <- newArray_ lu; return (IOUArray marr)
275     {-# INLINE unsafeRead #-}
276     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
277     {-# INLINE unsafeWrite #-}
278     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
279
280 instance MArray IOUArray Int64 IO where
281     {-# INLINE newArray #-}
282     newArray lu init = stToIO $ do
283         marr <- newArray lu init; return (IOUArray marr)
284     {-# INLINE newArray_ #-}
285     newArray_ lu = stToIO $ do
286         marr <- newArray_ lu; return (IOUArray marr)
287     {-# INLINE unsafeRead #-}
288     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
289     {-# INLINE unsafeWrite #-}
290     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
291
292 instance MArray IOUArray Word8 IO where
293     {-# INLINE newArray #-}
294     newArray lu init = stToIO $ do
295         marr <- newArray lu init; return (IOUArray marr)
296     {-# INLINE newArray_ #-}
297     newArray_ lu = stToIO $ do
298         marr <- newArray_ lu; return (IOUArray marr)
299     {-# INLINE unsafeRead #-}
300     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
301     {-# INLINE unsafeWrite #-}
302     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
303
304 instance MArray IOUArray Word16 IO where
305     {-# INLINE newArray #-}
306     newArray lu init = stToIO $ do
307         marr <- newArray lu init; return (IOUArray marr)
308     {-# INLINE newArray_ #-}
309     newArray_ lu = stToIO $ do
310         marr <- newArray_ lu; return (IOUArray marr)
311     {-# INLINE unsafeRead #-}
312     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
313     {-# INLINE unsafeWrite #-}
314     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
315
316 instance MArray IOUArray Word32 IO where
317     {-# INLINE newArray #-}
318     newArray lu init = stToIO $ do
319         marr <- newArray lu init; return (IOUArray marr)
320     {-# INLINE newArray_ #-}
321     newArray_ lu = stToIO $ do
322         marr <- newArray_ lu; return (IOUArray marr)
323     {-# INLINE unsafeRead #-}
324     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
325     {-# INLINE unsafeWrite #-}
326     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
327
328 instance MArray IOUArray Word64 IO where
329     {-# INLINE newArray #-}
330     newArray lu init = stToIO $ do
331         marr <- newArray lu init; return (IOUArray marr)
332     {-# INLINE newArray_ #-}
333     newArray_ lu = stToIO $ do
334         marr <- newArray_ lu; return (IOUArray marr)
335     {-# INLINE unsafeRead #-}
336     unsafeRead (IOUArray marr) i = stToIO (unsafeRead marr i)
337     {-# INLINE unsafeWrite #-}
338     unsafeWrite (IOUArray marr) i e = stToIO (unsafeWrite marr i e)
339
340 -----------------------------------------------------------------------------
341 -- Freezing
342
343 freezeIOArray :: Ix ix => IOArray ix e -> IO (Array ix e)
344 freezeIOArray (IOArray marr) = stToIO (freezeSTArray marr)
345
346 freezeIOUArray :: Ix ix => IOUArray ix e -> IO (UArray ix e)
347 freezeIOUArray (IOUArray marr) = stToIO (freezeSTUArray marr)
348
349 {-# RULES
350 "freeze/IOArray"  freeze = freezeIOArray
351 "freeze/IOUArray" freeze = freezeIOUArray
352     #-}
353
354 {-# INLINE unsafeFreezeIOArray #-}
355 unsafeFreezeIOArray :: Ix ix => IOArray ix e -> IO (Array ix e)
356 unsafeFreezeIOArray (IOArray marr) = stToIO (unsafeFreezeSTArray marr)
357
358 {-# INLINE unsafeFreezeIOUArray #-}
359 unsafeFreezeIOUArray :: Ix ix => IOUArray ix e -> IO (UArray ix e)
360 unsafeFreezeIOUArray (IOUArray marr) = stToIO (unsafeFreezeSTUArray marr)
361
362 {-# RULES
363 "unsafeFreeze/IOArray"  unsafeFreeze = unsafeFreezeIOArray
364 "unsafeFreeze/IOUArray" unsafeFreeze = unsafeFreezeIOUArray
365     #-}
366
367 -----------------------------------------------------------------------------
368 -- Thawing
369
370 thawIOArray :: Ix ix => Array ix e -> IO (IOArray ix e)
371 thawIOArray arr = stToIO $ do
372     marr <- thawSTArray arr
373     return (IOArray marr)
374
375 thawIOUArray :: Ix ix => UArray ix e -> IO (IOUArray ix e)
376 thawIOUArray arr = stToIO $ do
377     marr <- thawSTUArray arr
378     return (IOUArray marr)
379
380 {-# RULES
381 "thaw/IOArray"  thaw = thawIOArray
382 "thaw/IOUArray" thaw = thawIOUArray
383     #-}
384
385 {-# INLINE unsafeThawIOArray #-}
386 unsafeThawIOArray :: Ix ix => Array ix e -> IO (IOArray ix e)
387 unsafeThawIOArray arr = stToIO $ do
388     marr <- unsafeThawSTArray arr
389     return (IOArray marr)
390
391 {-# INLINE unsafeThawIOUArray #-}
392 unsafeThawIOUArray :: Ix ix => UArray ix e -> IO (IOUArray ix e)
393 unsafeThawIOUArray arr = stToIO $ do
394     marr <- unsafeThawSTUArray arr
395     return (IOUArray marr)
396
397 {-# RULES
398 "unsafeThaw/IOArray"  unsafeThaw = unsafeThawIOArray
399 "unsafeThaw/IOUArray" unsafeThaw = unsafeThawIOUArray
400     #-}
401
402 castSTUArray :: STUArray s ix a -> ST s (STUArray s ix b)
403 castSTUArray (STUArray l u marr#) = return (STUArray l u marr#)
404
405 -- | Casts an 'IOUArray' with one element type into one with a
406 -- different element type.  All the elements of the resulting array
407 -- are undefined (unless you know what you\'re doing...).
408 castIOUArray :: IOUArray ix a -> IO (IOUArray ix b)
409 castIOUArray (IOUArray marr) = stToIO $ do
410     marr' <- castSTUArray marr
411     return (IOUArray marr')
412
413 -- ---------------------------------------------------------------------------
414 -- hGetArray
415
416 -- | Reads a number of 'Word8's from the specified 'Handle' directly
417 -- into an array.
418 hGetArray
419         :: Handle               -- ^ Handle to read from
420         -> IOUArray Int Word8   -- ^ Array in which to place the values
421         -> Int                  -- ^ Number of 'Word8's to read
422         -> IO Int
423                 -- ^ Returns: the number of 'Word8's actually 
424                 -- read, which might be smaller than the number requested
425                 -- if the end of file was reached.
426
427 hGetArray handle (IOUArray (STUArray l u ptr)) count
428   | count <= 0 || count > rangeSize (l,u)
429   = illegalBufferSize handle "hGetArray" count
430   | otherwise = do
431       wantReadableHandle "hGetArray" handle $ 
432         \ handle_@Handle__{ haFD=fd, haBuffer=ref, haIsStream=is_stream } -> do
433         buf@Buffer{ bufBuf=raw, bufWPtr=w, bufRPtr=r } <- readIORef ref
434         if bufferEmpty buf
435            then readChunk fd is_stream ptr 0 count
436            else do 
437                 let avail = w - r
438                 copied <- if (count >= avail)
439                             then do 
440                                 memcpy_ba_baoff ptr raw r (fromIntegral avail)
441                                 writeIORef ref buf{ bufWPtr=0, bufRPtr=0 }
442                                 return avail
443                             else do 
444                                 memcpy_ba_baoff ptr raw r (fromIntegral count)
445                                 writeIORef ref buf{ bufRPtr = r + count }
446                                 return count
447
448                 let remaining = count - copied
449                 if remaining > 0 
450                    then do rest <- readChunk fd is_stream ptr copied remaining
451                            return (rest + count)
452                    else return count
453
454 readChunk :: FD -> Bool -> RawBuffer -> Int -> Int -> IO Int
455 readChunk fd is_stream ptr init_off bytes = loop init_off bytes 
456  where
457   loop :: Int -> Int -> IO Int
458   loop off bytes | bytes <= 0 = return (off - init_off)
459   loop off bytes = do
460     r' <- throwErrnoIfMinus1RetryMayBlock "readChunk"
461             (read_off_ba (fromIntegral fd) is_stream ptr 
462                 (fromIntegral off) (fromIntegral bytes))
463             (threadWaitRead fd)
464     let r = fromIntegral r'
465     if r == 0
466         then return (off - init_off)
467         else loop (off + r) (bytes - r)
468
469 -- ---------------------------------------------------------------------------
470 -- hPutArray
471
472 -- | Writes an array of 'Word8' to the specified 'Handle'.
473 hPutArray
474         :: Handle                       -- ^ Handle to write to
475         -> IOUArray Int Word8           -- ^ Array to write from
476         -> Int                          -- ^ Number of 'Word8's to write
477         -> IO ()
478
479 hPutArray handle (IOUArray (STUArray l u raw)) count
480   | count <= 0 || count > rangeSize (l,u)
481   = illegalBufferSize handle "hPutArray" count
482   | otherwise
483    = do wantWritableHandle "hPutArray" handle $ 
484           \ handle_@Handle__{ haFD=fd, haBuffer=ref, haIsStream=stream } -> do
485
486           old_buf@Buffer{ bufBuf=old_raw, bufRPtr=r, bufWPtr=w, bufSize=size }
487             <- readIORef ref
488
489           -- enough room in handle buffer?
490           if (size - w > count)
491                 -- There's enough room in the buffer:
492                 -- just copy the data in and update bufWPtr.
493             then do memcpy_baoff_ba old_raw w raw (fromIntegral count)
494                     writeIORef ref old_buf{ bufWPtr = w + count }
495                     return ()
496
497                 -- else, we have to flush
498             else do flushed_buf <- flushWriteBuffer fd stream old_buf
499                     writeIORef ref flushed_buf
500                     let this_buf = 
501                             Buffer{ bufBuf=raw, bufState=WriteBuffer, 
502                                     bufRPtr=0, bufWPtr=count, bufSize=count }
503                     flushWriteBuffer fd stream this_buf
504                     return ()
505
506 -- ---------------------------------------------------------------------------
507 -- Internal Utils
508
509 foreign import ccall unsafe "__hscore_memcpy_dst_off"
510    memcpy_baoff_ba :: RawBuffer -> Int -> RawBuffer -> CSize -> IO (Ptr ())
511 foreign import ccall unsafe "__hscore_memcpy_src_off"
512    memcpy_ba_baoff :: RawBuffer -> RawBuffer -> Int -> CSize -> IO (Ptr ())
513
514 illegalBufferSize :: Handle -> String -> Int -> IO a
515 illegalBufferSize handle fn sz = 
516         ioException (IOError (Just handle)
517                             InvalidArgument  fn
518                             ("illegal buffer size " ++ showsPrec 9 (sz::Int) [])
519                             Nothing)
520
521 #endif /* __GLASGOW_HASKELL__ */