Remove code that is dead now that we need >= 6.12 to build
[ghc-hetmet.git] / compiler / utils / FastString.lhs
index c095d6f..c6dac8f 100644 (file)
@@ -2,33 +2,39 @@
 % (c) The University of Glasgow, 1997-2006
 %
 \begin{code}
-{-# OPTIONS -w #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and fix
--- any warnings in the module. See
---     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
--- for details
+{-# LANGUAGE BangPatterns #-}
+{-# OPTIONS -fno-warn-unused-imports #-}
+-- XXX GHC 6.9 seems to be confused by unpackCString# being used only in
+--     a RULE
 
-{-
-FastString:     A compact, hash-consed, representation of character strings.
-                Comparison is O(1), and you can get a Unique from them.
-                Generated by the FSLIT macro
-                Turn into SDoc with Outputable.ftext
-
-LitString:      Just a wrapper for the Addr# of a C string (Ptr CChar).
-                Practically no operations
-                Outputing them is fast
-                Generated by the SLIT macro
-                Turn into SDoc with Outputable.ptext
-
-Use LitString unless you want the facilities of FastString
--}
+{-# OPTIONS_GHC -O -funbox-strict-fields #-}
+-- We always optimise this, otherwise performance of a non-optimised
+-- compiler is severely affected
+
+-- |
+-- There are two principal string types used internally by GHC:
+--
+-- 'FastString':
+--               * A compact, hash-consed, representation of character strings.
+--               * Comparison is O(1), and you can get a 'Unique.Unique' from them.
+--               * Generated by 'fsLit'.
+--               * Turn into 'Outputable.SDoc' with 'Outputable.ftext'.
+--
+-- 'LitString':
+--               * Just a wrapper for the @Addr#@ of a C string (@Ptr CChar@).
+--               * Practically no operations.
+--               * Outputing them is fast.
+--               * Generated by 'sLit'.
+--               * Turn into 'Outputable.SDoc' with 'Outputable.ptext'
+--
+-- Use 'LitString' unless you want the facilities of 'FastString'.
 module FastString
        (
         -- * FastStrings
         FastString(..),     -- not abstract, for now.
 
         -- ** Construction
+        fsLit,
         mkFastString,
         mkFastStringBytes,
         mkFastStringByteList,
@@ -67,39 +73,45 @@ module FastString
 
         -- * LitStrings
         LitString,
+        
+        -- ** Construction
+        sLit,
 #if defined(__GLASGOW_HASKELL__)
         mkLitString#,
-#else
-        mkLitString,
 #endif
+        mkLitString,
+        
+        -- ** Deconstruction
         unpackLitString,
-        strLength,
-
-        ptrStrLength
+        
+        -- ** Operations
+        lengthLS
        ) where
 
--- This #define suppresses the "import FastString" that
--- HsVersions otherwise produces
-#define COMPILING_FAST_STRING
 #include "HsVersions.h"
 
 import Encoding
 import FastTypes
 import FastFunctions
+import Panic
+import Util
 
-import Foreign
+import Foreign hiding   ( unsafePerformIO )
 import Foreign.C
 import GHC.Exts
+import System.IO
 import System.IO.Unsafe ( unsafePerformIO )
-import Control.Monad.ST ( stToIO )
+import Data.Data
 import Data.IORef       ( IORef, newIORef, readIORef, writeIORef )
-import System.IO        ( hPutBuf )
 import Data.Maybe       ( isJust )
 import Data.Char        ( ord )
 
-import GHC.ST
-import GHC.IOBase       ( IO(..) )
+import GHC.IO ( IO(..) )
+
 import GHC.Ptr          ( Ptr(..) )
+#if defined(__GLASGOW_HASKELL__)
+import GHC.Base         ( unpackCString# )
+#endif
 
 #define hASH_TBL_SIZE          4091
 #define hASH_TBL_SIZE_UNBOXED  4091#
@@ -120,7 +132,7 @@ data FastString = FastString {
       n_chars :: {-# UNPACK #-} !Int, -- number of chars
       buf     :: {-# UNPACK #-} !(ForeignPtr Word8),
       enc     :: FSEncoding
-  }
+  } deriving Typeable
 
 data FSEncoding
     -- including strings that don't need any encoding
@@ -146,6 +158,12 @@ instance Ord FastString where
 instance Show FastString where
    show fs = show (unpackFS fs)
 
+instance Data FastString where
+  -- don't traverse?
+  toConstr _   = abstractConstr "FastString"
+  gunfold _ _  = error "gunfold"
+  dataTypeOf _ = mkNoRepType "FastString"
+
 cmpFS :: FastString -> FastString -> Ordering
 cmpFS (FastString u1 l1 _ buf1 _) (FastString u2 l2 _ buf2 _) =
   if u1 == u2 then EQ else
@@ -205,7 +223,7 @@ mkFastString# a# = mkFastStringBytes ptr (ptrStrLength ptr)
 
 mkFastStringBytes :: Ptr Word8 -> Int -> FastString
 mkFastStringBytes ptr len = unsafePerformIO $ do
-  ft@(FastStringTable uid tbl#) <- readIORef string_table
+  ft@(FastStringTable uid _) <- readIORef string_table
   let
    h = hashStr ptr len
    add_it ls = do
@@ -225,7 +243,7 @@ mkFastStringBytes ptr len = unsafePerformIO $ do
 
 mkZFastStringBytes :: Ptr Word8 -> Int -> FastString
 mkZFastStringBytes ptr len = unsafePerformIO $ do
-  ft@(FastStringTable uid tbl#) <- readIORef string_table
+  ft@(FastStringTable uid _) <- readIORef string_table
   let
    h = hashStr ptr len
    add_it ls = do
@@ -248,7 +266,7 @@ mkZFastStringBytes ptr len = unsafePerformIO $ do
 -- the bytes if the string is new to the table.
 mkFastStringForeignPtr :: Ptr Word8 -> ForeignPtr Word8 -> Int -> IO FastString
 mkFastStringForeignPtr ptr fp len = do
-  ft@(FastStringTable uid tbl#) <- readIORef string_table
+  ft@(FastStringTable uid _) <- readIORef string_table
 --  _trace ("hashed: "++show (I# h)) $
   let
     h = hashStr ptr len
@@ -269,7 +287,7 @@ mkFastStringForeignPtr ptr fp len = do
 
 mkZFastStringForeignPtr :: Ptr Word8 -> ForeignPtr Word8 -> Int -> IO FastString
 mkZFastStringForeignPtr ptr fp len = do
-  ft@(FastStringTable uid tbl#) <- readIORef string_table
+  ft@(FastStringTable uid _) <- readIORef string_table
 --  _trace ("hashed: "++show (I# h)) $
   let
     h = hashStr ptr len
@@ -319,6 +337,7 @@ mkZFastString str =
       pokeCAString (castPtr ptr) str
       mkZFastStringForeignPtr ptr buf l
 
+bucket_match :: [FastString] -> Int -> Ptr Word8 -> IO (Maybe FastString)
 bucket_match [] _ _ = return Nothing
 bucket_match (v@(FastString _ l _ buf _):ls) len ptr
       | len == l  =  do
@@ -328,26 +347,31 @@ bucket_match (v@(FastString _ l _ buf _):ls) len ptr
       | otherwise =
          bucket_match ls len ptr
 
+mkNewFastString :: Int -> Ptr Word8 -> ForeignPtr Word8 -> Int
+                -> IO FastString
 mkNewFastString uid ptr fp len = do
   ref <- newIORef Nothing
   n_chars <- countUTF8Chars ptr len
   return (FastString uid len n_chars fp (UTF8Encoded ref))
 
-mkNewZFastString uid ptr fp len = do
+mkNewZFastString :: Int -> Ptr Word8 -> ForeignPtr Word8 -> Int
+                 -> IO FastString
+mkNewZFastString uid _ fp len = do
   return (FastString uid len len fp ZEncoded)
 
-
+copyNewFastString :: Int -> Ptr Word8 -> Int -> IO FastString
 copyNewFastString uid ptr len = do
   fp <- copyBytesToForeignPtr ptr len
   ref <- newIORef Nothing
   n_chars <- countUTF8Chars ptr len
   return (FastString uid len n_chars fp (UTF8Encoded ref))
 
+copyNewZFastString :: Int -> Ptr Word8 -> Int -> IO FastString
 copyNewZFastString uid ptr len = do
   fp <- copyBytesToForeignPtr ptr len
   return (FastString uid len len fp ZEncoded)
 
-
+copyBytesToForeignPtr :: Ptr Word8 -> Int -> IO (ForeignPtr Word8)
 copyBytesToForeignPtr ptr len = do
   fp <- mallocForeignPtrBytes len
   withForeignPtr fp $ \ptr' -> copyBytes ptr' ptr len
@@ -366,9 +390,9 @@ hashStr (Ptr a#) (I# len#) = loop 0# 0#
    where
     loop h n | n GHC.Exts.==# len# = I# h
              | otherwise  = loop h2 (n GHC.Exts.+# 1#)
-          where c = ord# (indexCharOffAddr# a# n)
-                h2 = (c GHC.Exts.+# (h GHC.Exts.*# 128#)) `remInt#`
-                     hASH_TBL_SIZE#
+          where !c = ord# (indexCharOffAddr# a# n)
+                !h2 = (c GHC.Exts.+# (h GHC.Exts.*# 128#)) `remInt#`
+                      hASH_TBL_SIZE#
 
 -- -----------------------------------------------------------------------------
 -- Operations
@@ -377,15 +401,15 @@ hashStr (Ptr a#) (I# len#) = loop 0# 0#
 lengthFS :: FastString -> Int
 lengthFS f = n_chars f
 
--- | Returns 'True' if the 'FastString' is Z-encoded
+-- | Returns @True@ if the 'FastString' is Z-encoded
 isZEncoded :: FastString -> Bool
 isZEncoded fs | ZEncoded <- enc fs = True
               | otherwise          = False
 
--- | Returns 'True' if this 'FastString' is not Z-encoded but already has
+-- | Returns @True@ if this 'FastString' is not Z-encoded but already has
 -- a Z-encoding cached (used in producing stats).
 hasZEncoding :: FastString -> Bool
-hasZEncoding fs@(FastString uid n_bytes _ fp enc) =
+hasZEncoding (FastString _ _ _ _ enc) =
   case enc of
     ZEncoded -> False
     UTF8Encoded ref ->
@@ -393,11 +417,11 @@ hasZEncoding fs@(FastString uid n_bytes _ fp enc) =
         m <- readIORef ref
         return (isJust m)
 
--- | Returns 'True' if the 'FastString' is empty
+-- | Returns @True@ if the 'FastString' is empty
 nullFS :: FastString -> Bool
 nullFS f  =  n_bytes f == 0
 
--- | unpacks and decodes the FastString
+-- | Unpacks and decodes the FastString
 unpackFS :: FastString -> String
 unpackFS (FastString _ n_bytes _ buf enc) =
   inlinePerformIO $ withForeignPtr buf $ \ptr ->
@@ -406,17 +430,17 @@ unpackFS (FastString _ n_bytes _ buf enc) =
         UTF8Encoded _ -> utf8DecodeString ptr n_bytes
 
 bytesFS :: FastString -> [Word8]
-bytesFS (FastString _ n_bytes _ buf enc) =
+bytesFS (FastString _ n_bytes _ buf _) =
   inlinePerformIO $ withForeignPtr buf $ \ptr ->
     peekArray n_bytes ptr
 
--- | returns a Z-encoded version of a 'FastString'.  This might be the
+-- | Returns a Z-encoded version of a 'FastString'.  This might be the
 -- original, if it was already Z-encoded.  The first time this
 -- function is applied to a particular 'FastString', the results are
 -- memoized.
 --
 zEncodeFS :: FastString -> FastString
-zEncodeFS fs@(FastString uid n_bytes _ fp enc) =
+zEncodeFS fs@(FastString _ _ _ _ enc) =
   case enc of
     ZEncoded -> fs
     UTF8Encoded ref ->
@@ -430,13 +454,25 @@ zEncodeFS fs@(FastString uid n_bytes _ fp enc) =
             return efs
 
 appendFS :: FastString -> FastString -> FastString
-appendFS fs1 fs2 = mkFastString (unpackFS fs1 ++ unpackFS fs2)
+appendFS fs1 fs2 =
+  inlinePerformIO $ do
+    r <- mallocForeignPtrBytes len
+    withForeignPtr r $ \ r' -> do
+    withForeignPtr (buf fs1) $ \ fs1Ptr -> do
+    withForeignPtr (buf fs2) $ \ fs2Ptr -> do
+        copyBytes r' fs1Ptr len1
+        copyBytes (advancePtr r' len1) fs2Ptr len2
+        mkFastStringForeignPtr r' r len
+  where len  = len1 + len2
+        len1 = lengthFS fs1
+        len2 = lengthFS fs2
 
 concatFS :: [FastString] -> FastString
 concatFS ls = mkFastString (Prelude.concat (map unpackFS ls)) -- ToDo: do better
 
 headFS :: FastString -> Char
-headFS (FastString _ n_bytes _ buf enc) =
+headFS (FastString _ 0 _ _ _) = panic "headFS: Empty FastString"
+headFS (FastString _ _ _ buf enc) =
   inlinePerformIO $ withForeignPtr buf $ \ptr -> do
     case enc of
       ZEncoded -> do
@@ -446,6 +482,7 @@ headFS (FastString _ n_bytes _ buf enc) =
          return (fst (utf8DecodeChar ptr))
 
 tailFS :: FastString -> FastString
+tailFS (FastString _ 0 _ _ _) = panic "tailFS: Empty FastString"
 tailFS (FastString _ n_bytes _ buf enc) =
   inlinePerformIO $ withForeignPtr buf $ \ptr -> do
     case enc of
@@ -462,6 +499,7 @@ consFS c fs = mkFastString (c : unpackFS fs)
 uniqueOfFS :: FastString -> FastInt
 uniqueOfFS (FastString u _ _ _ _) = iUnbox u
 
+nilFS :: FastString
 nilFS = mkFastString ""
 
 -- -----------------------------------------------------------------------------
@@ -478,6 +516,7 @@ getFastStringTable = do
 
 -- |Outputs a 'FastString' with /no decoding at all/, that is, you
 -- get the actual bytes in the 'FastString' written to the 'Handle'.
+hPutFS :: Handle -> FastString -> IO ()
 hPutFS handle (FastString _ len _ fp _)
   | len == 0  = return ()
   | otherwise = do withForeignPtr fp $ \ptr -> hPutBuf handle ptr len
@@ -500,7 +539,6 @@ type LitString = Ptr Word8
 mkLitString# :: Addr# -> LitString
 mkLitString# a# = Ptr a#
 #endif
-
 --can/should we use FastTypes here?
 --Is this likely to be memory-preserving if only used on constant strings?
 --should we inline it? If lucky, that would make a CAF that wouldn't
@@ -519,6 +557,9 @@ mkLitString s =
      loop n (c:cs) = do
         pokeByteOff p n (fromIntegral (ord c) :: Word8)
         loop (1+n) cs
+     -- XXX GHC isn't smart enough to know that we have already covered
+     -- this case.
+     loop _ [] = panic "mkLitString"
    loop 0 s
    return p
  )
@@ -531,8 +572,8 @@ unpackLitString p_ = case pUnbox p_ of
       ch -> if ch `eqFastChar` _CLIT('\0')
             then [] else cBox ch : unpack (n +# _ILIT(1))
 
-strLength :: LitString -> Int
-strLength = ptrStrLength
+lengthLS :: LitString -> Int
+lengthLS = ptrStrLength
 
 -- for now, use a simple String representation
 --no, let's not do that right now - it's work in other places
@@ -545,8 +586,8 @@ mkLitString = id
 unpackLitString :: LitString -> String
 unpackLitString = id
 
-strLength :: LitString -> Int
-strLength = length
+lengthLS :: LitString -> Int
+lengthLS = length
 
 #endif
 
@@ -562,12 +603,21 @@ foreign import ccall unsafe "ghc_strlen"
 pokeCAString :: Ptr CChar -> String -> IO ()
 pokeCAString ptr str =
   let
-        go [] n     = return ()
+        go [] _     = return ()
         go (c:cs) n = do pokeElemOff ptr n (castCharToCChar c); go cs (n+1)
   in
   go str 0
 
-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 602
-peekCAStringLen = peekCStringLen
-#endif
+{-# NOINLINE sLit #-}
+sLit :: String -> LitString
+sLit x  = mkLitString x
+
+{-# NOINLINE fsLit #-}
+fsLit :: String -> FastString
+fsLit x = mkFastString x
+
+{-# RULES "slit"
+    forall x . sLit  (unpackCString# x) = mkLitString#  x #-}
+{-# RULES "fslit"
+    forall x . fsLit (unpackCString# x) = mkFastString# x #-}
 \end{code}