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