bytestring 0.9.0.2 → 0.9.0.3
raw patch · 6 files changed
+137/−102 lines, 6 files
Files
- Data/ByteString.hs +21/−83
- Data/ByteString/Internal.hs +23/−13
- Data/ByteString/Lazy.hs +26/−4
- Data/ByteString/Lazy/Internal.hs +1/−1
- bytestring.cabal +1/−1
- tests/lazy-hclose.hs +65/−0
Data/ByteString.hs view
@@ -227,10 +227,10 @@ -- Control.Exception.bracket not available in yhc or nhc #ifndef __NHC__-import Control.Exception (bracket, assert)+import Control.Exception (finally, bracket, assert) import qualified Control.Exception as Exception #else-import IO (bracket)+import IO (bracket, finally) #endif import Control.Monad (when) @@ -1628,30 +1628,12 @@ memcpy p (f `plusPtr` s) (fromIntegral l) -- ------------------------------------------------------------------------ line IO+-- Line IO -- | Read a line from stdin. getLine :: IO ByteString getLine = hGetLine stdin -{---- | Lazily construct a list of lines of ByteStrings. This will be much--- better on memory consumption than using 'hGetContents >>= lines'--- If you're considering this, a better choice might be to use--- Data.ByteString.Lazy-hGetLines :: Handle -> IO [ByteString]-hGetLines h = go- where- go = unsafeInterleaveIO $ do- e <- hIsEOF h- if e- then return []- else do- x <- hGetLine h- xs <- go- return (x:xs)--}- -- | Read a line from a handle hGetLine :: Handle -> IO ByteString@@ -1751,9 +1733,13 @@ putStrLn :: ByteString -> IO () putStrLn = hPutStrLn stdout +------------------------------------------------------------------------+-- Low level IO+ -- | Read a 'ByteString' directly from the specified 'Handle'. This -- is far more efficient than reading the characters into a 'String' -- and then using 'pack'.+-- hGet :: Handle -> Int -> IO ByteString hGet _ 0 = return empty hGet h i = createAndTrim i $ \p -> hGetBuf h p i@@ -1761,6 +1747,7 @@ -- | hGetNonBlocking is identical to 'hGet', except that it will never block -- waiting for data to become available, instead it returns only whatever data -- is available.+-- hGetNonBlocking :: Handle -> Int -> IO ByteString #if defined(__GLASGOW_HASKELL__) hGetNonBlocking _ 0 = return empty@@ -1769,7 +1756,8 @@ hGetNonBlocking = hGet #endif --- | Read entire handle contents into a 'ByteString'.+-- | Read entire handle contents strictly into a 'ByteString'.+-- -- This function reads chunks at a time, doubling the chunksize on each -- read. The final buffer is then realloced to the appropriate size. For -- files > half of available memory, this may lead to memory exhaustion.@@ -1778,8 +1766,11 @@ -- As with 'hGet', the string representation in the file is assumed to -- be ISO-8859-1. --+-- The Handle is closed once the contents have been read,+-- or if an exception is thrown.+-- hGetContents :: Handle -> IO ByteString-hGetContents h = do+hGetContents h = always (hClose h) $ do -- strict, so hClose let start_size = 1024 p <- mallocBytes start_size i <- hGetBuf h p start_size@@ -1789,6 +1780,7 @@ return $! PS fp 0 i else f p start_size where+ always = flip finally f p s = do let s' = 2 * s p' <- reallocBytes p s'@@ -1800,14 +1792,17 @@ return $! PS fp 0 i' else f p' s' --- | getContents. Equivalent to hGetContents stdin+-- | getContents. Read stdin strictly. Equivalent to hGetContents stdin+-- The 'Handle' is closed after the contents have been read.+-- getContents :: IO ByteString getContents = hGetContents stdin -- | The interact function takes a function of type @ByteString -> ByteString@ -- 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. It's great for writing one line programs!+-- standard output device.+-- interact :: (ByteString -> ByteString) -> IO () interact transformer = putStr . transformer =<< getContents @@ -1816,6 +1811,7 @@ -- 'pack'. It also may be more efficient than opening the file and -- reading it using hGet. Files are read using 'binary mode' on Windows, -- for 'text mode' use the Char8 version of this function.+-- readFile :: FilePath -> IO ByteString readFile f = bracket (openBinaryFile f ReadMode) hClose (\h -> hFileSize h >>= hGet h . fromIntegral)@@ -1829,64 +1825,6 @@ appendFile :: FilePath -> ByteString -> IO () appendFile f txt = bracket (openBinaryFile f AppendMode) hClose (\h -> hPut h txt)--{------- Disable until we can move it into a portable .hsc file------- | Like readFile, this reads an entire file directly into a--- 'ByteString', but it is even more efficient. It involves directly--- mapping the file to memory. This has the advantage that the contents--- of the file never need to be copied. Also, under memory pressure the--- page may simply be discarded, while in the case of readFile it would--- need to be written to swap. If you read many small files, mmapFile--- will be less memory-efficient than readFile, since each mmapFile--- takes up a separate page of memory. Also, you can run into bus--- errors if the file is modified. As with 'readFile', the string--- representation in the file is assumed to be ISO-8859-1.------ On systems without mmap, this is the same as a readFile.----mmapFile :: FilePath -> IO ByteString-mmapFile f = mmap f >>= \(fp,l) -> return $! PS fp 0 l--mmap :: FilePath -> IO (ForeignPtr Word8, Int)-mmap f = do- h <- openBinaryFile f ReadMode- l <- fromIntegral `fmap` hFileSize h- -- Don't bother mmaping small files because each mmapped file takes up- -- at least one full VM block.- if l < mmap_limit- then do thefp <- mallocByteString l- withForeignPtr thefp $ \p-> hGetBuf h p l- hClose h- return (thefp, l)- else do- -- unix only :(- fd <- fromIntegral `fmap` handleToFd h- p <- my_mmap l fd- fp <- if p == nullPtr- then do thefp <- mallocByteString l- withForeignPtr thefp $ \p' -> hGetBuf h p' l- return thefp- else do- -- The munmap leads to crashes on OpenBSD.- -- maybe there's a use after unmap in there somewhere?- -- Bulat suggests adding the hClose to the- -- finalizer, excellent idea.-#if !defined(__OpenBSD__)- let unmap = c_munmap p l >> return ()-#else- let unmap = return ()-#endif- fp <- newForeignPtr p unmap- return fp- c_close fd- hClose h- return (fp, l)- where mmap_limit = 16*1024--} -- --------------------------------------------------------------------- -- Internal utilities
Data/ByteString/Internal.hs view
@@ -55,7 +55,7 @@ #endif -- * Chars- w2c, c2w, isSpaceWord8+ w2c, c2w, isSpaceWord8, isSpaceChar8 ) where @@ -268,20 +268,30 @@ c2w = fromIntegral . ord {-# INLINE c2w #-} --- Selects white-space characters in the Latin-1 range--- ordered by frequency--- Idea from Ketil+-- | Selects words corresponding to white-space characters in the Latin-1 range+-- ordered by frequency. isSpaceWord8 :: Word8 -> Bool-isSpaceWord8 w = case w of- 0x20 -> True -- SPACE- 0x0A -> True -- LF, \n- 0x09 -> True -- HT, \t- 0x0C -> True -- FF, \f- 0x0D -> True -- CR, \r- 0x0B -> True -- VT, \v- 0xA0 -> True -- spotted by QC..- _ -> False+isSpaceWord8 w =+ w == 0x20 ||+ w == 0x0A || -- LF, \n+ w == 0x09 || -- HT, \t+ w == 0x0C || -- FF, \f+ w == 0x0D || -- CR, \r+ w == 0x0B || -- VT, \v+ w == 0xA0 -- spotted by QC.. {-# INLINE isSpaceWord8 #-}++-- | Selects white-space characters in the Latin-1 range+isSpaceChar8 :: Char -> Bool+isSpaceChar8 c =+ c == ' ' ||+ c == '\t' ||+ c == '\n' ||+ c == '\r' ||+ c == '\f' ||+ c == '\v' ||+ c == '\xa0'+{-# INLINE isSpaceChar8 #-} ------------------------------------------------------------------------
Data/ByteString/Lazy.hs view
@@ -1172,13 +1172,20 @@ -- --------------------------------------------------------------------- -- Lazy ByteString IO+--+-- Rule for when to close: is it expected to read the whole file?+-- If so, close when done. +-- -- | Read entire handle contents /lazily/ into a 'ByteString'. Chunks -- are read on demand, in at most @k@-sized chunks. It does not block -- waiting for a whole @k@-sized chunk, so if less than @k@ bytes are -- available then they will be returned immediately as a smaller chunk.+--+-- The handle is closed on EOF.+-- hGetContentsN :: Int -> Handle -> IO ByteString-hGetContentsN k h = lazyRead+hGetContentsN k h = lazyRead -- TODO close on exceptions where lazyRead = unsafeInterleaveIO loop @@ -1189,7 +1196,7 @@ -- 0 or EAGAIN if S.null c then do eof <- hIsEOF h- if eof then return Empty+ if eof then hClose h >> return Empty else hWaitForInput h (-1) >> loop else do cs <- lazyRead@@ -1197,6 +1204,7 @@ -- | Read @n@ bytes into a 'ByteString', directly from the -- specified 'Handle', in chunks of size @k@.+-- hGetN :: Int -> Handle -> Int -> IO ByteString hGetN _ _ 0 = return empty hGetN k h n = readChunks n@@ -1212,9 +1220,10 @@ -- | hGetNonBlockingN is similar to 'hGetContentsN', except that it will never block -- waiting for data to become available, instead it returns only whatever data -- is available. Chunks are read on demand, in @k@-sized chunks.+-- hGetNonBlockingN :: Int -> Handle -> Int -> IO ByteString #if defined(__GLASGOW_HASKELL__)-hGetNonBlockingN _ _ 0 = return empty+hGetNonBlockingN _ _ 0 = return Empty hGetNonBlockingN k h n = readChunks n where STRICT1(readChunks)@@ -1230,10 +1239,14 @@ -- | Read entire handle contents /lazily/ into a 'ByteString'. Chunks -- are read on demand, using the default chunk size.+--+-- Once EOF is encountered, the Handle is closed.+-- hGetContents :: Handle -> IO ByteString hGetContents = hGetContentsN defaultChunkSize -- | Read @n@ bytes into a 'ByteString', directly from the specified 'Handle'.+-- hGet :: Handle -> Int -> IO ByteString hGet = hGetN defaultChunkSize @@ -1248,28 +1261,35 @@ #endif -- | Read an entire file /lazily/ into a 'ByteString'.+-- The Handle will be held open until EOF is encountered.+-- readFile :: FilePath -> IO ByteString readFile f = openBinaryFile f ReadMode >>= hGetContents -- | Write a 'ByteString' to a file.+-- writeFile :: FilePath -> ByteString -> IO () writeFile f txt = bracket (openBinaryFile f WriteMode) hClose (\hdl -> hPut hdl txt) -- | Append a 'ByteString' to a file.+-- appendFile :: FilePath -> ByteString -> IO () appendFile f txt = bracket (openBinaryFile f AppendMode) hClose (\hdl -> hPut hdl txt) -- | getContents. Equivalent to hGetContents stdin. Will read /lazily/+-- getContents :: IO ByteString getContents = hGetContents stdin -- | Outputs a 'ByteString' to the specified 'Handle'.+-- hPut :: Handle -> ByteString -> IO () hPut h cs = foldrChunks (\c rest -> S.hPut h c >> rest) (return ()) cs -- | A synonym for @hPut@, for compatibility+-- hPutStr :: Handle -> ByteString -> IO () hPutStr = hPut @@ -1278,13 +1298,15 @@ putStr = hPut stdout -- | Write a ByteString to stdout, appending a newline byte+-- putStrLn :: ByteString -> IO () putStrLn ps = hPut stdout ps >> hPut stdout (singleton 0x0a) -- | The interact function takes a function of type @ByteString -> ByteString@ -- 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. It's great for writing one line programs!+-- standard output device.+-- interact :: (ByteString -> ByteString) -> IO () interact transformer = putStr . transformer =<< getContents
Data/ByteString/Lazy/Internal.hs view
@@ -2,7 +2,7 @@ -- | -- Module : Data.ByteString.Lazy.Internal -- License : BSD-style--- Maintainer : dons@cse.unsw.edu.au, duncan@haskell.org+-- Maintainer : dons@galois.com, duncan@haskell.org -- Stability : experimental -- Portability : portable --
bytestring.cabal view
@@ -1,5 +1,5 @@ Name: bytestring-Version: 0.9.0.2+Version: 0.9.0.3 Synopsis: Fast, packed, strict and lazy byte arrays with a list interface Description: .
+ tests/lazy-hclose.hs view
@@ -0,0 +1,65 @@+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as S8++import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Lazy.Char8 as L8++import Control.Monad+import System.Directory+import System.Mem+import System.IO++import Data.ByteString.Internal+import Foreign.ForeignPtr++main = do+ writeFile "a" "x"++ ------------------------------------------------------------------------+ -- readFile tests++ print "Testing resource leaks for Strict.readFile"+ forM_ [1..n] $ const $ do+ r <- S.readFile "a"+ S.writeFile "b" (S8.pack "abc")+ renameFile "b" "a"++ print "Testing resource leaks for Lazy.readFile"+ forM_ [1..n] $ const $ do+ r <- L.readFile "a"+ L.length r `seq` return () -- force the input, and done with 'r' now.+ L.writeFile "b" (L8.pack "abc") -- but we still need the finalizers to run+ renameFile "b" "a"++ -- manage the resources explicitly.+ print "Testing resource leaks when converting lazy to strict"+ forM_ [1..n] $ const $ do+ let release c = finalizeForeignPtr fp where (fp,_,_) = toForeignPtr c+ r <- L.readFile "a"+ mapM_ release (L.toChunks r) -- should close it.+ L.writeFile "b" (L8.pack "abc")+ renameFile "b" "a"++ ------------------------------------------------------------------------+ -- hGetContents tests++ -- works now+ print "Testing strict hGetContents"+ forM_ [1..n] $ const $ do+ h <- openFile "a" ReadMode+ r <- S.hGetContents h -- should be strict, and hClosed.+ S.last r `seq` return ()+ S.writeFile "b" (S8.pack "abc")+ renameFile "b" "a"++ -- works now+ print "Testing lazy hGetContents"+ forM_ [1..n] $ const $ do+ h <- openFile "a" ReadMode+ r <- L.hGetContents h -- should be strict, and hClosed.+ L.last r `seq` return ()+ L.writeFile "b" (L8.pack "abc")+ renameFile "b" "a"+++n = 1000