@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, CPP, RecordWildCards #-}
1+{-# LANGUAGE BangPatterns, CPP, RecordWildCards, ScopedTypeVariables #-}
22-- |
33-- Module : Data.Text.IO
44-- Copyright : (c) Bryan O'Sullivan 2009,
@@ -32,15 +32,16 @@ module Data.Text.IO
3232 ) where
3333
3434import Data.Text (Text)
35−import Prelude hiding (appendFile, getContents, getLine, interact, putStr,
36− putStrLn, readFile, writeFile)
35+import Prelude hiding (appendFile, catch, getContents, getLine, interact,
36+ putStr, putStrLn, readFile, writeFile)
3737import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,
3838 withFile)
3939#if __GLASGOW_HASKELL__ <= 610
4040import qualified Data.ByteString.Char8 as B
4141import Data.Text.Encoding (decodeUtf8, encodeUtf8)
4242#else
43−import Control.Exception (throw)
43+import Control.Exception (catch, throw)
44+import Control.Monad (liftM2, when)
4445import Data.IORef (readIORef, writeIORef)
4546import qualified Data.Text as T
4647import Data.Text.Fusion (stream)
@@ -49,11 +50,13 @@ import Data.Text.IO.Internal (hGetLineWith, readChunk)
4950import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
5051 RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,
5152 writeCharBuf)
53+import GHC.IO.Exception (IOException(ioe_type), IOErrorType(InappropriateType))
5254import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,
5355 wantWritableHandle)
5456import GHC.IO.Handle.Text (commitBuffer')
5557import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),
5658 Newline(..))
59+import System.IO (hGetBuffering, hFileSize, hSetBuffering, hTell)
5760import System.IO.Error (isEOFError)
5861#endif
5962
@@ -87,7 +90,9 @@ hGetContents :: Handle -> IO Text
8790#if __GLASGOW_HASKELL__ <= 610
8891hGetContents = fmap decodeUtf8 . B.hGetContents
8992#else
90−hGetContents h = wantReadableHandle "hGetContents" h $ \hh -> do
93+hGetContents h = do
94+ chooseGoodBuffering h
95+ wantReadableHandle "hGetContents" h $ \hh -> do
9196 (hh',ts) <- readAll hh
9297 return (hh',T.concat ts)
9398 where
@@ -106,6 +111,23 @@ hGetContents h = wantReadableHandle "hGetContents" h $ \hh -> do
106111 else throw (augmentIOError e "hGetContents" h)
107112#endif
108113
114+-- | Use a more efficient buffer size if we're reading in
115+-- block-buffered mode with the default buffer size. When we can
116+-- determine the size of the handle we're reading, set the buffer size
117+-- to that, so that we can read the entire file in one chunk.
118+-- Otherwise, use a buffer size of at least 16KB.
119+chooseGoodBuffering :: Handle -> IO ()
120+chooseGoodBuffering h = do
121+ bufMode <- hGetBuffering h
122+ case bufMode of
123+ BlockBuffering Nothing -> do
124+ d <- catch (liftM2 (-) (hFileSize h) (hTell h)) $ \(e::IOException) ->
125+ if ioe_type e == InappropriateType
126+ then return 16384 -- faster than the 2KB default
127+ else throw e
128+ when (d > 0) . hSetBuffering h . BlockBuffering . Just . fromIntegral $ d
129+ _ -> return ()
130+
109131-- | Read a single line from a handle.
110132hGetLine :: Handle -> IO Text
111133#if __GLASGOW_HASKELL__ <= 610