@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, CPP, RecordWildCards #-}
1+{-# LANGUAGE BangPatterns, CPP, RecordWildCards, ScopedTypeVariables #-}
3-- Module : Data.Text.IO
3-- Module : Data.Text.IO
4-- Copyright : (c) Bryan O'Sullivan 2009,
4-- Copyright : (c) Bryan O'Sullivan 2009,
@@ -32,15 +32,16 @@ module Data.Text.IO
34import Data.Text (Text)
34import Data.Text (Text)
35−import Prelude hiding (appendFile, getContents, getLine, interact, putStr,
35+import Prelude hiding (appendFile, catch, getContents, getLine, interact,
36− putStrLn, readFile, writeFile)
36+ putStr, putStrLn, readFile, writeFile)
37import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,
37import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,
39#if __GLASGOW_HASKELL__ <= 610
39#if __GLASGOW_HASKELL__ <= 610
40import qualified Data.ByteString.Char8 as B
40import qualified Data.ByteString.Char8 as B
41import Data.Text.Encoding (decodeUtf8, encodeUtf8)
41import Data.Text.Encoding (decodeUtf8, encodeUtf8)
43−import Control.Exception (throw)
43+import Control.Exception (catch, throw)
44+import Control.Monad (liftM2, when)
44import Data.IORef (readIORef, writeIORef)
45import Data.IORef (readIORef, writeIORef)
45import qualified Data.Text as T
46import qualified Data.Text as T
46import Data.Text.Fusion (stream)
47import Data.Text.Fusion (stream)
@@ -49,11 +50,13 @@ import Data.Text.IO.Internal (hGetLineWith, readChunk)
49import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
50import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
50 RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,
51 RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,
51 writeCharBuf)
52 writeCharBuf)
53+import GHC.IO.Exception (IOException(ioe_type), IOErrorType(InappropriateType))
52import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,
54import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,
53 wantWritableHandle)
55 wantWritableHandle)
54import GHC.IO.Handle.Text (commitBuffer')
56import GHC.IO.Handle.Text (commitBuffer')
55import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),
57import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),
56 Newline(..))
58 Newline(..))
59+import System.IO (hGetBuffering, hFileSize, hSetBuffering, hTell)
57import System.IO.Error (isEOFError)
60import System.IO.Error (isEOFError)
@@ -87,7 +90,9 @@ hGetContents :: Handle -> IO Text
87#if __GLASGOW_HASKELL__ <= 610
90#if __GLASGOW_HASKELL__ <= 610
88hGetContents = fmap decodeUtf8 . B.hGetContents
91hGetContents = fmap decodeUtf8 . B.hGetContents
94+ chooseGoodBuffering h
90−hGetContents h = wantReadableHandle "hGetContents" h $ \hh -> do
95+ wantReadableHandle "hGetContents" h $ \hh -> do
91 (hh',ts) <- readAll hh
96 (hh',ts) <- readAll hh
92 return (hh',T.concat ts)
97 return (hh',T.concat ts)
@@ -106,6 +111,23 @@ hGetContents h = wantReadableHandle "hGetContents" h $ \hh -> do
106 else throw (augmentIOError e "hGetContents" h)
111 else throw (augmentIOError e "hGetContents" h)
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
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
128+ when (d > 0) . hSetBuffering h . BlockBuffering . Just . fromIntegral $ d
109-- | Read a single line from a handle.
131-- | Read a single line from a handle.
110hGetLine :: Handle -> IO Text
132hGetLine :: Handle -> IO Text
111#if __GLASGOW_HASKELL__ <= 610
133#if __GLASGOW_HASKELL__ <= 610