text 0.7 → 0.7.0.1
raw patch · 7 files changed
+93/−63 lines, 7 filesdep +extensible-exceptions
Dependencies added: extensible-exceptions
Files
- Data/Text.hs +5/−1
- Data/Text/Encoding/Error.hs +5/−1
- Data/Text/Lazy.hs +5/−1
- Data/Text/Lazy/Encoding/Fusion.hs +45/−43
- Data/Text/Lazy/IO.hs +13/−11
- tests/Benchmarks.hs +12/−1
- text.cabal +8/−5
Data/Text.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE BangPatterns, Rank2Types #-}+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- |@@ -167,7 +167,9 @@ Read(..), Show(..), (&&), (||), (+), (-), (.), ($), (>>), (*), div, not, return, otherwise)+#if defined(HAVE_DEEPSEQ) import Control.DeepSeq (NFData)+#endif import Control.Exception (assert) import Data.Char (isSpace) import Control.Monad (foldM)@@ -215,7 +217,9 @@ instance IsString Text where fromString = pack +#if defined(HAVE_DEEPSEQ) instance NFData Text+#endif -- ----------------------------------------------------------------------------- -- * Conversion to/from 'Text'
Data/Text/Encoding/Error.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE CPP, DeriveDataTypeable #-} -- | -- Module : Data.Text.Encoding.Error -- Copyright : (c) Bryan O'Sullivan 2009@@ -35,7 +35,11 @@ , replace ) where +#if __GLASGOW_HASKELL__ >= 610 import Control.Exception (Exception, throw)+#else+import Control.Exception.Extensible (Exception, throw)+#endif import Data.Typeable (Typeable) import Data.Word (Word8) import Numeric (showHex)
Data/Text/Lazy.hs view
@@ -1,5 +1,5 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BangPatterns, CPP #-} -- | -- Module : Data.Text.Lazy -- Copyright : (c) Bryan O'Sullivan 2009@@ -169,7 +169,9 @@ (&&), (+), (-), (.), ($), (++), div, flip, fromIntegral, not, otherwise) import qualified Prelude as P+#if defined(HAVE_DEEPSEQ) import Control.DeepSeq (NFData(..))+#endif import Data.Int (Int64) import qualified Data.List as L import Data.Char (isSpace)@@ -208,9 +210,11 @@ instance IsString Text where fromString = pack +#if defined(HAVE_DEEPSEQ) instance NFData Text where rnf Empty = () rnf (Chunk _ ts) = rnf ts+#endif -- | /O(n)/ Convert a 'String' into a 'Text'. --
Data/Text/Lazy/Encoding/Fusion.hs view
@@ -35,7 +35,6 @@ import Data.Text.Encoding.Fusion.Common import Data.Text.Encoding.Error import Data.Text.Fusion (Step(..), Stream(..))-import Data.Text.Fusion.Internal (M(..), PairS(..), S(..)) import Data.Text.Fusion.Size import Data.Text.UnsafeChar (unsafeChr8) import Data.Word (Word8)@@ -47,51 +46,54 @@ import Control.Exception (assert) import qualified Data.ByteString.Internal as B +data S = S0+ | S1 {-# UNPACK #-} !Word8+ | S2 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8+ | S3 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8+ | S4 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8++data T = T {-# UNPACK #-} !ByteString {-# UNPACK #-} !S {-# UNPACK #-} !Int+ -- | /O(n)/ Convert a lazy 'ByteString' into a 'Stream Char', using -- UTF-8 encoding. streamUtf8 :: OnDecodeError -> ByteString -> Stream Char-streamUtf8 onErr bs0 = Stream next (bs0 :*: empty :*: 0) unknownSize- where- empty = S N N N N- next (bs@(Chunk ps _) :*: S N _ _ _ :*: i)- | i < len && U8.validate1 a =- Yield (unsafeChr8 a) (bs :*: empty :*: i+1)- | i + 1 < len && U8.validate2 a b =- Yield (U8.chr2 a b) (bs :*: empty :*: i+2)- | i + 2 < len && U8.validate3 a b c =- Yield (U8.chr3 a b c) (bs :*: empty :*: i+3)- | i + 4 < len && U8.validate4 a b c d =- Yield (U8.chr4 a b c d) (bs :*: empty :*: i+4)- where len = B.length ps- a = B.unsafeIndex ps i- b = B.unsafeIndex ps (i+1)- c = B.unsafeIndex ps (i+2)- d = B.unsafeIndex ps (i+3)- next st@(bs :*: s :*: i) =- case s of- S (J a) N _ _ | U8.validate1 a ->- Yield (unsafeChr8 a) es- S (J a) (J b) N _ | U8.validate2 a b ->- Yield (U8.chr2 a b) es- S (J a) (J b) (J c) N | U8.validate3 a b c ->- Yield (U8.chr3 a b c) es- S (J a) (J b) (J c) (J d) | U8.validate4 a b c d ->- Yield (U8.chr4 a b c d) es- _ -> consume st- where es = bs :*: empty :*: i- consume (bs@(Chunk ps rest) :*: s :*: i)- | i >= B.length ps = consume (rest :*: s :*: 0)- | otherwise =- case s of- S N _ _ _ -> next (bs :*: S x N N N :*: i+1)- S a N _ _ -> next (bs :*: S a x N N :*: i+1)- S a b N _ -> next (bs :*: S a b x N :*: i+1)- S a b c N -> next (bs :*: S a b c x :*: i+1)- S (J a) b c d -> decodeError "streamUtf8" "UTF-8" onErr (Just a)- (bs :*: S b c d N :*: i+1)- where x = J (B.unsafeIndex ps i)- consume (Empty :*: S N _ _ _ :*: _) = Done- consume st = decodeError "streamUtf8" "UTF-8" onErr Nothing st+streamUtf8 onErr bs0 = Stream next (T bs0 S0 0) unknownSize+ where+ next (T bs@(Chunk ps _) S0 i)+ | i < len && U8.validate1 a =+ Yield (unsafeChr8 a) (T bs S0 (i+1))+ | i + 1 < len && U8.validate2 a b =+ Yield (U8.chr2 a b) (T bs S0 (i+2))+ | i + 2 < len && U8.validate3 a b c =+ Yield (U8.chr3 a b c) (T bs S0 (i+3))+ | i + 4 < len && U8.validate4 a b c d =+ Yield (U8.chr4 a b c d) (T bs S0 (i+4))+ where len = B.length ps+ a = B.unsafeIndex ps i+ b = B.unsafeIndex ps (i+1)+ c = B.unsafeIndex ps (i+2)+ d = B.unsafeIndex ps (i+3)+ next st@(T bs s i) =+ case s of+ S1 a | U8.validate1 a -> Yield (unsafeChr8 a) es+ S2 a b | U8.validate2 a b -> Yield (U8.chr2 a b) es+ S3 a b c | U8.validate3 a b c -> Yield (U8.chr3 a b c) es+ S4 a b c d | U8.validate4 a b c d -> Yield (U8.chr4 a b c d) es+ _ -> consume st+ where es = T bs S0 i+ consume (T bs@(Chunk ps rest) s i)+ | i >= B.length ps = consume (T rest s 0)+ | otherwise =+ case s of+ S0 -> next (T bs (S1 x) (i+1))+ S1 a -> next (T bs (S2 a x) (i+1))+ S2 a b -> next (T bs (S3 a b x) (i+1))+ S3 a b c -> next (T bs (S4 a b c x) (i+1))+ S4 a b c d -> decodeError "streamUtf8" "UTF-8" onErr (Just a)+ (T bs (S3 b c d) (i+1))+ where x = B.unsafeIndex ps i+ consume (T Empty S0 _) = Done+ consume st = decodeError "streamUtf8" "UTF-8" onErr Nothing st {-# INLINE [0] streamUtf8 #-} -- | /O(n)/ Convert a 'Stream' 'Word8' to a lazy 'ByteString'.
Data/Text/Lazy/IO.hs view
@@ -8,7 +8,7 @@ -- Stability : experimental -- Portability : GHC ----- Efficient locale-sensitive support for text I\/O.+-- Efficient locale-sensitive support for lazy text I\/O. module Data.Text.Lazy.IO (@@ -31,7 +31,7 @@ , putStrLn ) where -import Data.Text.Lazy.Internal (Text(..))+import Data.Text.Lazy (Text) import Prelude hiding (appendFile, getContents, getLine, interact, putStr, putStrLn, readFile, writeFile) import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,@@ -39,13 +39,14 @@ import qualified Data.Text.IO as T import qualified Data.Text.Lazy as L #if __GLASGOW_HASKELL__ <= 610-import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)+import Data.Text.Lazy.Encoding (decodeUtf8) import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Lazy.Char8 as L8 #else import Control.Exception (throw) import Data.IORef (readIORef) import Data.Text.IO.Internal (hGetLineWith, readChunk)+import Data.Text.Lazy.Internal (chunk, empty) import GHC.IO.Buffer (isEmptyBuffer) import GHC.IO.Exception (IOException(..), IOErrorType(..), ioException) import GHC.IO.Handle.Internals (augmentIOError, hClose_help,@@ -55,9 +56,8 @@ import System.IO.Unsafe (unsafeInterleaveIO) #endif --- | The 'readFile' function reads a file and returns the contents of--- the file as a string. The entire file is read strictly, as with--- 'getContents'.+-- | Read a file and return its contents as a string. The file is+-- read lazily, as with 'getContents'. readFile :: FilePath -> IO Text readFile name = openFile name ReadMode >>= hGetContents @@ -70,6 +70,8 @@ appendFile :: FilePath -> Text -> IO () appendFile p = withFile p AppendMode . flip hPutStr +-- | Lazily read the remaining contents of a 'Handle'. The 'Handle'+-- will be closed after the read completes, or on error. hGetContents :: Handle -> IO Text #if __GLASGOW_HASKELL__ <= 610 hGetContents = fmap decodeUtf8 . L8.hGetContents@@ -94,11 +96,11 @@ buf <- readIORef haCharBuffer (do t <- readChunk hh buf ts <- lazyRead h- return (hh, Chunk t ts)) `catch` \e -> do+ return (hh, chunk t ts)) `catch` \e -> do (hh', _) <- hClose_help hh if isEOFError e then return $ if isEmptyBuffer buf- then (hh', Empty)+ then (hh', empty) else (hh', L.singleton '\r') else throw (augmentIOError e "hGetContents" h) #endif@@ -121,12 +123,12 @@ -- | The 'interact' function takes a function of type @Text -> Text@ -- as its argument. The entire input from the standard input device is--- passed to this function as its argument, and the resulting string--- is output on the standard output device.+-- passed (lazily) to this function as its argument, and the resulting+-- string is output on the standard output device. interact :: (Text -> Text) -> IO () interact f = putStr . f =<< getContents --- | Read all user input on 'stdin' as a single string.+-- | Lazily read all user input on 'stdin' as a single string. getContents :: IO Text getContents = hGetContents stdin
tests/Benchmarks.hs view
@@ -9,11 +9,14 @@ import Data.Char import qualified Codec.Binary.UTF8.Generic as UTF8 import qualified Data.Text as TS+import qualified Data.Text.IO as TS import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.IO as TL import qualified Data.List as L import qualified Data.Text.Encoding as TS import qualified Data.Text.Lazy.Encoding as TL import qualified Criterion.MultiMap as M+import Control.DeepSeq import Criterion.Config import GHC.Base @@ -38,7 +41,8 @@ rnf (B b) = rnf b main = do- bsa <- BS.readFile "text/test/russian.txt"+ let dataFile = "text/test/russian.txt"+ bsa <- BS.readFile dataFile let tsa = TS.decodeUtf8 bsa tsb = TS.toUpper tsa tla = TL.fromChunks (TS.chunksOf 16376 tsa)@@ -191,6 +195,13 @@ , bench "bs" $ nf (BS.map f . BS.map f) bsa , bench "bl" $ nf (BL.map f . BL.map f) bla , bench "l" $ nf (L.map f . L.map f) la+ ],+ bgroup "readFile" [+ bench "ts" $ TS.readFile dataFile+ , bench "tl" $ nfIO (TL.readFile dataFile)+ , bench "bs" $ BS.readFile dataFile+ , bench "bl" $ nfIO (BL.length `fmap` BL.readFile dataFile)+ , bench "l" $ nfIO (length `fmap` readFile dataFile) ], bgroup "replicate char" [ bench "ts" $ nf (TS.replicate bsa_len) (TS.singleton c)
text.cabal view
@@ -1,5 +1,5 @@ name: text-version: 0.7+version: 0.7.0.1 synopsis: An efficient packed Unicode text type description: An efficient packed Unicode text type. license: BSD3@@ -11,7 +11,7 @@ copyright: 2008-2009 Tom Harper, 2009 Bryan O'Sullivan category: Data, Text build-type: Simple-cabal-version: >= 1.2+cabal-version: >= 1.2.3 extra-source-files: README TODO@@ -67,11 +67,14 @@ build-depends: base < 5,- bytestring >= 0.9 && < 1.0,- deepseq >= 1.1.0.0+ bytestring >= 0.9 && < 1.0 if impl(ghc >= 6.10) build-depends:- ghc-prim, base >= 4+ ghc-prim, base >= 4, deepseq >= 1.1.0.0+ cpp-options: -DHAVE_DEEPSEQ+ else+ build-depends: extensible-exceptions+ extensions: PatternSignatures -- gather extensive profiling data for now ghc-prof-options: -auto-all