never executed always true always false
1 {-# LANGUAGE BangPatterns #-}
2
3 -----------------------------------------------------------------------------
4 --
5 -- Fast write-buffered Handles
6 --
7 -- (c) The University of Glasgow 2005-2006
8 --
9 -- This is a simple abstraction over Handles that offers very fast write
10 -- buffering, but without the thread safety that Handles provide. It's used
11 -- to save time in GHC.Utils.Ppr.printDoc.
12 --
13 -----------------------------------------------------------------------------
14
15 module GHC.Utils.BufHandle (
16 BufHandle(..),
17 newBufHandle,
18 bPutChar,
19 bPutStr,
20 bPutFS,
21 bPutFZS,
22 bPutPtrString,
23 bPutReplicate,
24 bFlush,
25 ) where
26
27 import GHC.Prelude
28
29 import GHC.Data.FastString
30 import GHC.Data.FastMutInt
31
32 import Control.Monad ( when )
33 import Data.ByteString (ByteString)
34 import qualified Data.ByteString.Unsafe as BS
35 import Data.Char ( ord )
36 import Foreign
37 import Foreign.C.String
38 import System.IO
39
40 -- -----------------------------------------------------------------------------
41
42 data BufHandle = BufHandle {-#UNPACK#-}!(Ptr Word8)
43 {-#UNPACK#-}!FastMutInt
44 Handle
45
46 newBufHandle :: Handle -> IO BufHandle
47 newBufHandle hdl = do
48 ptr <- mallocBytes buf_size
49 r <- newFastMutInt 0
50 return (BufHandle ptr r hdl)
51
52 buf_size :: Int
53 buf_size = 8192
54
55 bPutChar :: BufHandle -> Char -> IO ()
56 bPutChar b@(BufHandle buf r hdl) !c = do
57 i <- readFastMutInt r
58 if (i >= buf_size)
59 then do hPutBuf hdl buf buf_size
60 writeFastMutInt r 0
61 bPutChar b c
62 else do pokeElemOff buf i (fromIntegral (ord c) :: Word8)
63 writeFastMutInt r (i+1)
64
65 bPutStr :: BufHandle -> String -> IO ()
66 bPutStr (BufHandle buf r hdl) !str = do
67 i <- readFastMutInt r
68 loop str i
69 where loop "" !i = do writeFastMutInt r i; return ()
70 loop (c:cs) !i
71 | i >= buf_size = do
72 hPutBuf hdl buf buf_size
73 loop (c:cs) 0
74 | otherwise = do
75 pokeElemOff buf i (fromIntegral (ord c))
76 loop cs (i+1)
77
78 bPutFS :: BufHandle -> FastString -> IO ()
79 bPutFS b fs = bPutBS b $ bytesFS fs
80
81 bPutFZS :: BufHandle -> FastZString -> IO ()
82 bPutFZS b fs = bPutBS b $ fastZStringToByteString fs
83
84 bPutBS :: BufHandle -> ByteString -> IO ()
85 bPutBS b bs = BS.unsafeUseAsCStringLen bs $ bPutCStringLen b
86
87 bPutCStringLen :: BufHandle -> CStringLen -> IO ()
88 bPutCStringLen b@(BufHandle buf r hdl) cstr@(ptr, len) = do
89 i <- readFastMutInt r
90 if (i + len) >= buf_size
91 then do hPutBuf hdl buf i
92 writeFastMutInt r 0
93 if (len >= buf_size)
94 then hPutBuf hdl ptr len
95 else bPutCStringLen b cstr
96 else do
97 copyBytes (buf `plusPtr` i) ptr len
98 writeFastMutInt r (i + len)
99
100 bPutPtrString :: BufHandle -> PtrString -> IO ()
101 bPutPtrString b@(BufHandle buf r hdl) l@(PtrString a len) = l `seq` do
102 i <- readFastMutInt r
103 if (i+len) >= buf_size
104 then do hPutBuf hdl buf i
105 writeFastMutInt r 0
106 if (len >= buf_size)
107 then hPutBuf hdl a len
108 else bPutPtrString b l
109 else do
110 copyBytes (buf `plusPtr` i) a len
111 writeFastMutInt r (i+len)
112
113 -- | Replicate an 8-bit character
114 bPutReplicate :: BufHandle -> Int -> Char -> IO ()
115 bPutReplicate (BufHandle buf r hdl) len c = do
116 i <- readFastMutInt r
117 let oc = fromIntegral (ord c)
118 if (i+len) < buf_size
119 then do
120 fillBytes (buf `plusPtr` i) oc len
121 writeFastMutInt r (i+len)
122 else do
123 -- flush the current buffer
124 when (i /= 0) $ hPutBuf hdl buf i
125 if (len < buf_size)
126 then do
127 fillBytes buf oc len
128 writeFastMutInt r len
129 else do
130 -- fill a full buffer
131 fillBytes buf oc buf_size
132 -- flush it as many times as necessary
133 let go n | n >= buf_size = do
134 hPutBuf hdl buf buf_size
135 go (n-buf_size)
136 | otherwise = writeFastMutInt r n
137 go len
138
139 bFlush :: BufHandle -> IO ()
140 bFlush (BufHandle buf r hdl) = do
141 i <- readFastMutInt r
142 when (i > 0) $ hPutBuf hdl buf i
143 free buf
144 return ()