% (c) The University of Glasgow, 1997-2006
%
\begin{code}
-{-
-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 -fno-warn-unused-imports #-}
+-- XXX GHC 6.9 seems to be confused by unpackCString# being used only in
+-- a RULE
+
+{-# 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,
-- * LitStrings
LitString,
+
+ -- ** Construction
+ sLit,
#if defined(__GLASGOW_HASKELL__)
mkLitString#,
-#else
- mkLitString,
#endif
+ mkLitString,
+
+ -- ** Deconstruction
unpackLitString,
- strLength,
-
- ptrStrLength
+
+ -- ** Operations
+ lengthLS
) where
#include "HsVersions.h"
import System.IO.Unsafe ( unsafePerformIO )
import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
import Data.Maybe ( isJust )
-#if !defined(__GLASGOW_HASKELL__)
import Data.Char ( ord )
-#endif
import GHC.IOBase ( 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#
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 (FastString _ _ _ _ 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 ->
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.
#if defined(__GLASGOW_HASKELL__)
mkLitString# :: Addr# -> LitString
mkLitString# a# = Ptr a#
-#else
+#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
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
)
-#endif
unpackLitString :: LitString -> String
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
unpackLitString :: LitString -> String
unpackLitString = id
-strLength :: LitString -> Int
-strLength = length
+lengthLS :: LitString -> Int
+lengthLS = length
#endif
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}