X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=Data%2FArray%2FIO.hs;h=b47e147dc2ae613bc87209d3881cede3d3ceff04;hb=746ef6a7fd71bb1e9ebe3cd107c5f9f79f3b7a68;hp=9e7892ef5089660209b186c23fa9a591047296d4;hpb=7f1f4e7a695c402ddd3a1dc2cc7114e649a78ebc;p=ghc-base.git diff --git a/Data/Array/IO.hs b/Data/Array/IO.hs index 9e7892e..b47e147 100644 --- a/Data/Array/IO.hs +++ b/Data/Array/IO.hs @@ -1,5 +1,6 @@ +{-# OPTIONS -#include "HsBase.h" #-} ----------------------------------------------------------------------------- --- +-- | -- Module : Data.Array.IO -- Copyright : (c) The University of Glasgow 2001 -- License : BSD-style (see the file libraries/core/LICENSE) @@ -8,8 +9,6 @@ -- Stability : experimental -- Portability : non-portable -- --- $Id: IO.hs,v 1.1 2001/06/28 14:15:02 simonmar Exp $ --- -- Mutable boxed/unboxed arrays in the IO monad. -- ----------------------------------------------------------------------------- @@ -19,6 +18,8 @@ module Data.Array.IO ( IOArray, -- instance of: Eq, Typeable IOUArray, -- instance of: Eq, Typeable castIOUArray, -- :: IOUArray i a -> IO (IOUArray i b) + hGetArray, -- :: Handle -> IOUArray Int Word8 -> Int -> IO Int + hPutArray, -- :: Handle -> IOUArray Int Word8 -> Int -> IO () ) where import Prelude @@ -29,6 +30,7 @@ import Data.Int import Data.Word import Data.Dynamic +import Foreign.C import Foreign.Ptr ( Ptr, FunPtr ) import Foreign.StablePtr ( StablePtr ) @@ -40,7 +42,10 @@ import GHC.Arr ( STArray, freezeSTArray, unsafeFreezeSTArray, thawSTArray, unsafeThawSTArray ) import GHC.ST ( ST(..) ) -import GHC.IOBase ( stToIO ) + +import GHC.IOBase +import GHC.Handle +import GHC.Conc import GHC.Base @@ -362,4 +367,101 @@ castIOUArray (IOUArray marr) = stToIO $ do marr' <- castSTUArray marr return (IOUArray marr') +-- --------------------------------------------------------------------------- +-- hGetArray + +hGetArray :: Handle -> IOUArray Int Word8 -> Int -> IO Int +hGetArray handle (IOUArray (STUArray l u ptr)) count + | count <= 0 || count > rangeSize (l,u) + = illegalBufferSize handle "hGetArray" count + | otherwise = do + wantReadableHandle "hGetArray" handle $ + \ handle_@Handle__{ haFD=fd, haBuffer=ref, haIsStream=is_stream } -> do + buf@Buffer{ bufBuf=raw, bufWPtr=w, bufRPtr=r } <- readIORef ref + if bufferEmpty buf + then readChunk fd is_stream ptr 0 count + else do + let avail = w - r + copied <- if (count >= avail) + then do + memcpy_ba_baoff ptr raw r (fromIntegral avail) + writeIORef ref buf{ bufWPtr=0, bufRPtr=0 } + return avail + else do + memcpy_ba_baoff ptr raw r (fromIntegral count) + writeIORef ref buf{ bufRPtr = r + count } + return count + + let remaining = count - copied + if remaining > 0 + then do rest <- readChunk fd is_stream ptr copied remaining + return (rest + count) + else return count + +readChunk :: FD -> Bool -> RawBuffer -> Int -> Int -> IO Int +readChunk fd is_stream ptr init_off bytes = loop init_off bytes + where + loop :: Int -> Int -> IO Int + loop off bytes | bytes <= 0 = return (off - init_off) + loop off bytes = do + r' <- throwErrnoIfMinus1RetryMayBlock "readChunk" + (read_off_ba (fromIntegral fd) is_stream ptr + (fromIntegral off) (fromIntegral bytes)) + (threadWaitRead fd) + let r = fromIntegral r' + if r == 0 + then return (off - init_off) + else loop (off + r) (bytes - r) + +-- --------------------------------------------------------------------------- +-- hPutArray + +hPutArray + :: Handle -- handle to write to + -> IOUArray Int Word8 -- buffer + -> Int -- number of bytes of data to write + -> IO () + +hPutArray handle (IOUArray (STUArray l u raw)) count + | count <= 0 || count > rangeSize (l,u) + = illegalBufferSize handle "hPutArray" count + | otherwise + = do wantWritableHandle "hPutArray" handle $ + \ handle_@Handle__{ haFD=fd, haBuffer=ref, haIsStream=stream } -> do + + old_buf@Buffer{ bufBuf=old_raw, bufRPtr=r, bufWPtr=w, bufSize=size } + <- readIORef ref + + -- enough room in handle buffer? + if (size - w > count) + -- There's enough room in the buffer: + -- just copy the data in and update bufWPtr. + then do memcpy_baoff_ba old_raw w raw (fromIntegral count) + writeIORef ref old_buf{ bufWPtr = w + count } + return () + + -- else, we have to flush + else do flushed_buf <- flushWriteBuffer fd stream old_buf + writeIORef ref flushed_buf + let this_buf = + Buffer{ bufBuf=raw, bufState=WriteBuffer, + bufRPtr=0, bufWPtr=count, bufSize=count } + flushWriteBuffer fd stream this_buf + return () + +-- --------------------------------------------------------------------------- +-- Internal Utils + +foreign import ccall unsafe "__hscore_memcpy_dst_off" + memcpy_baoff_ba :: RawBuffer -> Int -> RawBuffer -> CSize -> IO (Ptr ()) +foreign import ccall unsafe "__hscore_memcpy_src_off" + memcpy_ba_baoff :: RawBuffer -> RawBuffer -> Int -> CSize -> IO (Ptr ()) + +illegalBufferSize :: Handle -> String -> Int -> IO a +illegalBufferSize handle fn sz = + ioException (IOError (Just handle) + InvalidArgument fn + ("illegal buffer size " ++ showsPrec 9 (sz::Int) []) + Nothing) + #endif /* __GLASGOW_HASKELL__ */