[project @ 1998-08-24 19:16:32 by sof]
[ghc-hetmet.git] / ghc / lib / misc / PackedString.lhs
index 752891a..f27d8b5 100644 (file)
@@ -1,5 +1,5 @@
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
 %
 \section{Packed strings}
 
@@ -21,7 +21,6 @@ module PackedString (
        unsafeByteArrayToPS, -- :: ByteArray a   -> Int -> PackedString
 
        psToByteArray,       -- :: PackedString  -> ByteArray Int
-       psToByteArrayST,     -- :: PackedString  -> ST s (ByteArray Int)
        psToCString,         -- :: PackedString  -> Addr
         isCString,          -- :: PackedString  -> Bool
 
@@ -29,11 +28,9 @@ module PackedString (
        unpackNBytesPS,  -- :: PackedString -> Int -> [Char]
        unpackPSIO,      -- :: PackedString -> IO [Char]
 
-{-LATER:
        hPutPS,      -- :: Handle -> PackedString -> IO ()
-        putPS,       -- :: FILE -> PackedString -> PrimIO () -- ToDo: more sensible type
-       getPS,       -- :: FILE -> Int -> PrimIO PackedString
--}
+       hGetPS,      -- :: Handle -> Int -> IO PackedString
+
        nilPS,       -- :: PackedString
        consPS,      -- :: Char -> PackedString -> PackedString
        headPS,      -- :: PackedString -> Char
@@ -70,28 +67,25 @@ module PackedString (
          -}
        substrPS,    -- :: PackedString -> Int -> Int -> PackedString
 
-       comparePS,
-
-         -- Converting to C strings
-       packCString#, 
-       unpackCString#,
-       unpackCString2#,
-       unpackAppendCString#,
-       unpackFoldrCString#,
-       unpackCString,
-       unpackCStringIO,
-       unpackCStringLenIO
+       comparePS    -- :: PackedString -> PackedString -> Ordering
 
     ) where
 
 import GlaExts
 import PrelBase ( showList__  ) -- ToDo: better
+import PrelPack
+         (  new_ps_array
+         ,  freeze_ps_array
+         ,  write_ps_array
+         )
 import Addr
 
 import PrelArr  ( StateAndMutableByteArray#(..) , StateAndByteArray#(..) )
 import PrelST
 import ST
 import IOExts   ( unsafePerformIO )
+import IO
+import PrelHandle ( hFillBufBA )
 
 import Ix
 import Char (isSpace)
@@ -247,7 +241,7 @@ packNCharsST len@(I# length#) str =
    -- fill in packed string from "str"
  fill_in ch_array 0# str   >>
    -- freeze the puppy:
- freeze_ps_array ch_array >>= \ (ByteArray _ frozen#) ->
+ freeze_ps_array ch_array length# >>= \ (ByteArray _ frozen#) ->
  let has_null = byteArrayHasNUL# frozen# length# in
  return (PS frozen# length# has_null)
  where
@@ -368,6 +362,7 @@ unpackPS (CPS addr len)
 unpackNBytesPS :: PackedString -> Int -> [Char]
 unpackNBytesPS ps len@(I# l#)
  | len < 0     = error ("PackedString.unpackNBytesPS: negative length "++ show len)
+ | len == 0     = []
  | otherwise    =
     case ps of
       PS bytes len# has_null -> unpackPS (PS bytes (min# len# l#) has_null)
@@ -395,152 +390,30 @@ unpackPSIO (CPS addr len)
 Output a packed string via a handle:
 
 \begin{code}
-{- LATER:
 hPutPS :: Handle -> PackedString -> IO ()
-hPutPS handle ps = 
- let
-  len = 
-   case ps of
-    PS  _ len _ -> len
-    CPS _ len   -> len
- in
- if len ==# 0# then
-    return ()
- else
-    _readHandle handle                             >>= \ htype ->
-    case htype of 
-      _ErrorHandle ioError ->
-         _writeHandle handle htype                 >>
-          failWith ioError
-      _ClosedHandle ->
-         _writeHandle handle htype                 >>
-         failWith (IllegalOperation "handle is closed")
-      _SemiClosedHandle _ _ ->
-         _writeHandle handle htype                 >>
-         failWith (IllegalOperation "handle is closed")
-      _ReadHandle _ _ _ ->
-         _writeHandle handle htype                 >>
-         failWith (IllegalOperation "handle is not open for writing")
-      other -> 
-          _getBufferMode other                     >>= \ other ->
-          (case _bufferMode other of
-            Just LineBuffering ->
-               writeLines (_filePtr other)
-            Just (BlockBuffering (Just size)) ->
-               writeBlocks (_filePtr other) size
-            Just (BlockBuffering Nothing) ->
-               writeBlocks (_filePtr other) ``BUFSIZ''
-            _ -> -- Nothing is treated pessimistically as NoBuffering
-               writeChars (_filePtr other) 0#
-         )                                         >>= \ success ->
-           _writeHandle handle (_markHandle other) >>
-          if success then
-              return ()
-          else
-              _constructError "hPutStr"            >>= \ ioError ->
-             failWith ioError
-
+hPutPS handle (CPS a# len#)    = hPutBuf    handle (A# a#) (I# len#)
+hPutPS handle (PS  ba# len# _) = hPutBufBA  handle (ByteArray bottom ba#) (I# len#)
   where
-    pslen = lengthPS# ps
-
-    writeLines :: Addr -> IO Bool
-    writeLines = writeChunks ``BUFSIZ'' True 
-
-    writeBlocks :: Addr -> Int -> IO Bool
-    writeBlocks fp size = writeChunks size False fp
-     {-
-       The breaking up of output into lines along \n boundaries
-       works fine as long as there are newlines to split by.
-       Avoid the splitting up into lines altogether (doesn't work
-       for overly long lines like the stuff that showsPrec instances
-       normally return). Instead, we split them up into fixed size
-       chunks before blasting them off to the Real World.
-
-       Hacked to avoid multiple passes over the strings - unsightly, but
-       a whole lot quicker. -- SOF 3/96
-     -}
-
-    writeChunks :: Int -> Bool -> Addr -> IO Bool
-    writeChunks (I# bufLen) chopOnNewLine fp =
-     newCharArray (0,I# bufLen) >>= \ arr@(MutableByteArray _ arr#) ->
-     let
-      shoveString :: Int# -> Int# -> IO Bool
-      shoveString n i 
-       | i ==# pslen =   -- end of string
-          if n ==# 0# then
-             return True
-          else
-             _ccall_ writeFile arr fp (I# n) >>= \rc ->
-             return (rc==0)
-       | otherwise =
-          (\ (S# s#) ->
-              case writeCharArray# arr# n (indexPS# ps i) s# of
-               s1# -> 
-                  {- Flushing lines - should we bother? -}
-                 (if n ==# bufLen then
-                     _ccall_ writeFile arr fp (I# (n +# 1#)) >>= \rc ->
-                    if rc == 0 then
-                       shoveString 0# (i +# 1#)
-                     else
-                       return False
-                   else
-                      shoveString (n +# 1#) (i +# 1#)) (S# s1#))
-     in
-     shoveString 0# 0#
-
-    writeChars :: Addr -> Int# -> IO Bool
-    writeChars fp i 
-      | i ==# pslen = return True
-      | otherwise  =
-       _ccall_ filePutc fp (ord (C# (indexPS# ps i)))  >>= \ rc ->
-        if rc == 0 then
-           writeChars fp (i +# 1#)
-       else
-           return False
-
----------------------------------------------
-
-putPS :: _FILE -> PackedString -> IO ()
-putPS file ps@(PS bytes len has_null)
-  | len ==# 0#
-  = return ()
-  | otherwise
-  = let
-       byte_array = ByteArray (0, I# (len -# 1#)) bytes
-    in
-    _ccall_ fwrite byte_array (1::Int){-size-} (I# len) file
-                                       >>= \ (I# written) ->
-    if written ==# len then
-       return ()
-    else
-       error "putPS: fwrite failed!\n"
-
-putPS file (CPS addr len)
-  | len ==# 0#
-  = return ()
-  | otherwise
-  = _ccall_ fputs (A# addr) file >>= \ (I# _){-force type-} ->
-    return ()
+    bottom = error "hPutPS"
 \end{code}
 
 The dual to @_putPS@, note that the size of the chunk specified
 is the upper bound of the size of the chunk returned.
 
 \begin{code}
-getPS :: _FILE -> Int -> IO PackedString
-getPS file len@(I# len#)
+hGetPS :: Handle -> Int -> IO PackedString
+hGetPS hdl len@(I# len#)
  | len# <=# 0# = return nilPS -- I'm being kind here.
  | otherwise   =
     -- Allocate an array for system call to store its bytes into.
-   new_ps_array len#      >>= \ ch_arr ->
-   freeze_ps_array ch_arr >>= \ (ByteArray _ frozen#) ->
+   stToIO (new_ps_array len# )          >>= \ ch_arr ->
+   stToIO (freeze_ps_array ch_arr len#)  >>= \ (ByteArray _ frozen#) ->
    let
     byte_array = ByteArray (0, I# len#) frozen#
    in
-   _ccall_ fread byte_array (1::Int) len file >>= \  (I# read#) ->
+   hFillBufBA hdl byte_array len >>= \  (I# read#) ->
    if read# ==# 0# then -- EOF or other error
-      error "getPS: EOF reached or other error"
+      fail (userError "hGetPS: EOF reached or other error")
    else
      {-
        The system call may not return the number of
@@ -553,7 +426,7 @@ getPS file len@(I# len#)
       has_null = byteArrayHasNUL# frozen# read#
      in 
      return (PS frozen# read# has_null)
-END LATER -}
+
 \end{code}
 
 %************************************************************************
@@ -629,19 +502,12 @@ nullPS :: PackedString -> Bool
 nullPS (PS  _ i _) = i ==# 0#
 nullPS (CPS _ i)   = i ==# 0#
 
-{- (ToDo: some non-lousy implementations...)
-
-    Old : _appendPS xs  ys = packString (unpackPS xs ++ unpackPS ys)
-
--}
 appendPS :: PackedString -> PackedString -> PackedString
 appendPS xs ys
   | nullPS xs = ys
   | nullPS ys = xs
   | otherwise  = concatPS [xs,ys]
 
-{- OLD: mapPS f xs = packString (map f (unpackPS xs)) -}
-
 mapPS :: (Char -> Char) -> PackedString -> PackedString {-or String?-}
 mapPS f xs = 
   if nullPS xs then
@@ -650,7 +516,7 @@ mapPS f xs =
      runST (
        new_ps_array (length +# 1#)         >>= \ ps_arr ->
        whizz ps_arr length 0#              >>
-       freeze_ps_array ps_arr             >>= \ (ByteArray _ frozen#) ->
+       freeze_ps_array ps_arr length       >>= \ (ByteArray _ frozen#) ->
        let has_null = byteArrayHasNUL# frozen# length in
        return (PS frozen# length has_null))
   where
@@ -703,9 +569,9 @@ filterPS pred ps =
        else if len_filtered# ==# 0# then
         return nilPS
        else
-         new_ps_array (len_filtered# +# 1#) >>= \ ps_arr ->
-         copy_arr ps_arr rle 0# 0#          >>
-         freeze_ps_array ps_arr                    >>= \ (ByteArray _ frozen#) ->
+         new_ps_array (len_filtered# +# 1#)   >>= \ ps_arr ->
+         copy_arr ps_arr rle 0# 0#            >>
+         freeze_ps_array ps_arr len_filtered# >>= \ (ByteArray _ frozen#) ->
          let has_null = byteArrayHasNUL# frozen# len_filtered# in
          return (PS frozen# len_filtered# has_null))
   where
@@ -882,7 +748,7 @@ reversePS ps =
     runST (
       new_ps_array (length +# 1#)    >>= \ arr# -> -- incl NUL byte!
       fill_in arr# (length -# 1#) 0# >>
-      freeze_ps_array arr#          >>= \ (ByteArray _ frozen#) ->
+      freeze_ps_array arr# length    >>= \ (ByteArray _ frozen#) ->
       let has_null = byteArrayHasNUL# frozen# length in
       return (PS frozen# length has_null))
  where
@@ -910,7 +776,7 @@ concatPS pss
     runST (
     new_ps_array (tot_len# +# 1#)   >>= \ arr# -> -- incl NUL byte!
     packum arr# pss 0#             >>
-    freeze_ps_array arr#           >>= \ (ByteArray _ frozen#) ->
+    freeze_ps_array arr# tot_len#   >>= \ (ByteArray _ frozen#) ->
 
     let has_null = byteArrayHasNUL# frozen# tot_len# in
          
@@ -1010,9 +876,9 @@ substrPS# ps s e
 
   | otherwise
   = runST (
-       new_ps_array (result_len# +# 1#) >>= \ ch_arr -> -- incl NUL byte!
-       fill_in ch_arr 0#                >>
-       freeze_ps_array ch_arr           >>= \ (ByteArray _ frozen#) ->
+       new_ps_array (result_len# +# 1#)   >>= \ ch_arr -> -- incl NUL byte!
+       fill_in ch_arr 0#                  >>
+       freeze_ps_array ch_arr result_len# >>= \ (ByteArray _ frozen#) ->
 
        let has_null = byteArrayHasNUL# frozen# result_len# in
          
@@ -1039,30 +905,6 @@ substrPS# ps s e
        fill_in arr_in# (idx +# 1#)
 \end{code}
 
-(Very :-) ``Specialised'' versions of some CharArray things...
-
-\begin{code}
-new_ps_array   :: Int# -> ST s (MutableByteArray s Int)
-write_ps_array :: MutableByteArray s Int -> Int# -> Char# -> ST s () 
-freeze_ps_array :: MutableByteArray s Int -> ST s (ByteArray Int)
-
-new_ps_array size = ST $ \ s# ->
-    case newCharArray# size s#  of { StateAndMutableByteArray# s2# barr# ->
-    STret s2# (MutableByteArray bot barr#)}
-  where
-    bot = error "new_ps_array"
-
-write_ps_array (MutableByteArray _ barr#) n ch = ST $ \ s# ->
-    case writeCharArray# barr# n ch s# of { s2#   ->
-    STret s2# ()}
-
--- same as unsafeFreezeByteArray
-freeze_ps_array (MutableByteArray ixs arr#) = ST $ \ s# ->
-    case unsafeFreezeByteArray# arr# s# of { StateAndByteArray# s2# frozen# ->
-    STret s2# (ByteArray ixs frozen#) }
-\end{code}
-
-
 %*********************************************************
 %*                                                     *
 \subsection{Packing and unpacking C strings}
@@ -1070,100 +912,12 @@ freeze_ps_array (MutableByteArray ixs arr#) = ST $ \ s# ->
 %*********************************************************
 
 \begin{code}
-unpackCString :: Addr -> [Char]
-
--- Calls to the next four are injected by the compiler itself, 
--- to deal with literal strings
-packCString#        :: [Char]          -> ByteArray#
-unpackCString#       :: Addr#           -> [Char]
-unpackCString2#      :: Addr# -> Int#   -> [Char]
-unpackAppendCString# :: Addr# -> [Char] -> [Char]
-unpackFoldrCString#  :: Addr# -> (Char  -> a -> a) -> a -> a 
-
-packCString# str = case (packString str) of { PS bytes _ _ -> bytes }
-
-unpackCString a@(A# addr) = 
- if a == ``NULL'' then
-    []
- else
-    unpackCString# addr
-
-unpackCString# addr
-  = unpack 0#
-  where
-    unpack nh
-      | ch `eqChar#` '\0'# = []
-      | otherwise         = C# ch : unpack (nh +# 1#)
-      where
-       ch = indexCharOffAddr# addr nh
-
-unpackCStringIO :: Addr -> IO String
-unpackCStringIO addr = unpack 0#
-  where
-    unpack nh = do
-       ch <- readCharOffAddr addr (I# nh)
-       if ch == '\0'
-        then return []
-       else do
-          ls <- unpack (nh +# 1#)
-          return (ch : ls)
-
--- unpack 'len' chars
-unpackCStringLenIO :: Addr -> Int -> IO String
-unpackCStringLenIO addr l@(I# len#)
- | len# <# 0#  = fail (userError ("PackedString.unpackCStringLenIO: negative length (" ++ show l ++ ")"))
- | otherwise   = unpack len#
-  where
-    unpack 0# = return []
-    unpack nh = do
-       ch <- readCharOffAddr addr (I# nh)
-       ls <- unpack (nh -# 1#)
-       return (ch : ls)
-
-
-unpackCString2# addr len
-  -- This one is called by the compiler to unpack literal strings with NULs in them; rare.
-  = unpackPS (packCBytes (I# len) (A# addr))
-
-unpackAppendCString# addr rest
-  = unpack 0#
-  where
-    unpack nh
-      | ch `eqChar#` '\0'# = rest
-      | otherwise         = C# ch : unpack (nh +# 1#)
-      where
-       ch = indexCharOffAddr# addr nh
-
-unpackFoldrCString# addr f z 
-  = unpack 0#
-  where
-    unpack nh
-      | ch `eqChar#` '\0'# = z
-      | otherwise         = C# ch `f` unpack (nh +# 1#)
-      where
-       ch = indexCharOffAddr# addr nh
-
-
 cStringToPS     :: Addr  -> PackedString
 cStringToPS (A# a#) =  -- the easy one; we just believe the caller
  CPS a# len
  where
   len = case (strlen# a#) of { I# x -> x }
 
-packBytesForC :: [Char] -> ByteArray Int
-packBytesForC str = psToByteArray (packString str)
-
-psToByteArrayST :: [Char] -> ST s (ByteArray Int)
-psToByteArrayST str =
-  packStringST str     >>= \ (PS bytes n has_null) -> 
-   --later? ASSERT(not has_null)
-  return (ByteArray (0, I# (n -# 1#)) bytes)
-
-packNBytesForCST :: Int -> [Char] -> ST s (ByteArray Int)
-packNBytesForCST len str =
-  packNCharsST len str >>= \ (PS bytes n has_null) -> 
-  return (ByteArray (0, I# (n -# 1#)) bytes)
-
 packCBytes :: Int -> Addr -> PackedString
 packCBytes len addr = runST (packCBytesST len addr)
 
@@ -1177,7 +931,7 @@ packCBytesST len@(I# length#) (A# addr) =
    -- fill in packed string from "addr"
   fill_in ch_array 0#   >>
    -- freeze the puppy:
-  freeze_ps_array ch_array >>= \ (ByteArray _ frozen#) ->
+  freeze_ps_array ch_array length# >>= \ (ByteArray _ frozen#) ->
   let has_null = byteArrayHasNUL# frozen# length# in
   return (PS frozen# length# has_null)
   where