Skip to content

Commit

Permalink
contains error do not pull, added NoShrink
Browse files Browse the repository at this point in the history
  • Loading branch information
BebeSparkelSparkel committed May 24, 2024
1 parent 13f5ed1 commit eb4b004
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 45 deletions.
71 changes: 32 additions & 39 deletions src/Data/Text/IO.hs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{-# LANGUAGE BangPatterns, CPP, RecordWildCards, ScopedTypeVariables #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NamedFieldPuns #-}
-- |
-- Module : Data.Text.IO
-- Copyright : (c) 2009, 2010 Bryan O'Sullivan,
Expand Down Expand Up @@ -42,6 +43,7 @@ module Data.Text.IO
, putStrLn
) where

import Data.Bool (bool)
import Data.Text (Text)
import Prelude hiding (appendFile, getContents, getLine, interact,
putStr, putStrLn, readFile, writeFile)
Expand All @@ -54,9 +56,9 @@ import qualified Data.Text as T
import Data.Text.Internal.Fusion (stream)
import Data.Text.Internal.Fusion.Types (Step(..), Stream(..))
import Data.Text.Internal.IO (hGetLineWith, readChunk)
import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,
writeCharBuf)
import GHC.IO.Buffer (Buffer(..), BufferState(..), RawCharBuffer, CharBuffer,
emptyBuffer, isEmptyBuffer, newCharBuffer)
import qualified GHC.IO.Buffer
import GHC.IO.Exception (IOException(ioe_type), IOErrorType(InappropriateType))
import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,
wantWritableHandle)
Expand Down Expand Up @@ -184,9 +186,7 @@ hPutStr h t = do
case buffer_mode of
(NoBuffering, _) -> hPutChars h str
(LineBuffering, buf) -> writeLines h nl buf str
(BlockBuffering _, buf)
| nl == CRLF -> writeBlocksCRLF h buf str
| otherwise -> writeBlocksRaw h buf str
(BlockBuffering _, buf) -> writeBlocks (nl == CRLF) h buf str

hPutChars :: Handle -> Stream Char -> IO ()
hPutChars h (Stream next0 s0 _len) = loop s0
Expand All @@ -206,55 +206,48 @@ hPutChars h (Stream next0 s0 _len) = loop s0
-- performance improvement. Lifting out the raw/cooked newline
-- handling gave a few more percent on top.

writeLines :: Handle -> Newline -> Buffer CharBufElem -> Stream Char -> IO ()
writeLines :: Handle -> Newline -> CharBuffer -> Stream Char -> IO ()
writeLines h nl buf0 (Stream next0 s0 _len) = outer s0 buf0
where
outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)
outer s1 buf@Buffer{..} = inner s1 (0::Int)
where
inner !s !n =
case next0 s of
Done -> commit n False{-no flush-} True{-release-} >> return ()
Skip s' -> inner s' n
Yield x s'
| n + 1 >= len -> commit n True{-needs flush-} False >>= outer s
| n + 1 >= bufSize -> commit n True{-needs flush-} False >>= outer s
| x == '\n' -> do
n' <- if nl == CRLF
then do n1 <- writeCharBuf raw n '\r'
writeCharBuf raw n1 '\n'
else writeCharBuf raw n x
then do n1 <- writeCharBuf bufRaw bufSize n '\r'
writeCharBuf bufRaw bufSize n1 '\n'
else writeCharBuf bufRaw bufSize n x
commit n' True{-needs flush-} False >>= outer s'
| otherwise -> writeCharBuf raw n x >>= inner s'
commit = commitBuffer h raw len
| otherwise -> writeCharBuf bufRaw bufSize n x >>= inner s'
commit = commitBuffer h buf

writeBlocksCRLF :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()
writeBlocksCRLF h buf0 (Stream next0 s0 _len) = outer s0 buf0
writeBlocks :: Bool -> Handle -> CharBuffer -> Stream Char -> IO ()
writeBlocks isCRLF h buf0 (Stream next0 s0 _len) = outer s0 buf0
where
outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)
outer s1 buf@Buffer{..} = inner s1 (0::Int)
where
inner !s !n =
case next0 s of
Done -> commit n False{-no flush-} True{-release-} >> return ()
Skip s' -> inner s' n
Yield x s'
| n + 1 >= len -> commit n True{-needs flush-} False >>= outer s
| x == '\n' -> do n1 <- writeCharBuf raw n '\r'
writeCharBuf raw n1 '\n' >>= inner s'
| otherwise -> writeCharBuf raw n x >>= inner s'
commit = commitBuffer h raw len
| n >= bufSize + bool 10 10 (isCRLF && x == '\n') ->
commit n True{-needs flush-} False >>= outer s
| isCRLF && x == '\n' -> do
n1 <- writeCharBuf bufRaw bufSize n '\r'
writeCharBuf bufRaw bufSize n1 '\n' >>= inner s'
| otherwise -> writeCharBuf bufRaw bufSize n x >>= inner s'
commit = commitBuffer h buf

writeBlocksRaw :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()
writeBlocksRaw h buf0 (Stream next0 s0 _len) = outer s0 buf0
where
outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)
where
inner !s !n =
case next0 s of
Done -> commit n False{-no flush-} True{-release-} >> return ()
Skip s' -> inner s' n
Yield x s'
| n + 1 >= len -> commit n True{-needs flush-} False >>= outer s
| otherwise -> writeCharBuf raw n x >>= inner s'
commit = commitBuffer h raw len
-- | Only modifies the raw buffer and not the buffer attributes
writeCharBuf :: RawCharBuffer -> Int -> Int -> Char -> IO Int
writeCharBuf bufRaw bufSize n c = E.assert (n >= 0 && n < bufSize) $
GHC.IO.Buffer.writeCharBuf bufRaw n c

-- This function is completely lifted from GHC.IO.Handle.Text.
getSpareBuffer :: Handle__ -> IO (BufferMode, CharBuffer)
Expand All @@ -276,12 +269,12 @@ getSpareBuffer Handle__{haCharBuffer=ref,
return (mode, new_buf)


-- This function is completely lifted from GHC.IO.Handle.Text.
commitBuffer :: Handle -> RawCharBuffer -> Int -> Int -> Bool -> Bool
-- This function is modified from GHC.Internal.IO.Handle.Text.
commitBuffer :: Handle -> CharBuffer -> Int -> Bool -> Bool
-> IO CharBuffer
commitBuffer hdl !raw !sz !count flush release =
commitBuffer hdl Buffer{bufRaw, bufSize} !count flush release =
wantWritableHandle "commitAndReleaseBuffer" hdl $
commitBuffer' raw sz count flush release
commitBuffer' bufRaw bufSize count flush release
{-# INLINE commitBuffer #-}

-- | Write a string to a handle, followed by a newline.
Expand Down
16 changes: 10 additions & 6 deletions tests/Tests/QuickCheckUtils.hs
Original file line number Diff line number Diff line change
Expand Up @@ -258,14 +258,14 @@ write_read :: forall a b c.
-> [TestTree]
write_read unline filt writer reader modData
= encodings <&> \enc@TextEncoding {textEncodingName} -> testGroup textEncodingName
[ testProperty "NoBuffering" $ noShrinking $ propTest enc (pure IO.NoBuffering)
, testProperty "LineBuffering" $ noShrinking $ propTest enc (pure IO.LineBuffering)
, testProperty "BlockBuffering" $ noShrinking $ propTest enc blockBuffering
[ testProperty "NoBuffering" $ propTest enc (pure IO.NoBuffering)
, testProperty "LineBuffering" $ propTest enc (pure IO.LineBuffering)
, testProperty "BlockBuffering" $ propTest enc blockBuffering
]
where
propTest :: TextEncoding -> Gen IO.BufferMode -> IO.NewlineMode -> c -> Property
propTest _ _ (IO.NewlineMode IO.LF IO.CRLF) _ = discard
propTest enc genBufferMode nl d = forAll genBufferMode $ \mode -> ioProperty $ withTempFile $ \_ h -> do
propTest :: TextEncoding -> Gen IO.BufferMode -> NoShrink IO.NewlineMode -> c -> Property
propTest _ _ (NoShrink (IO.NewlineMode IO.LF IO.CRLF)) _ = discard
propTest enc genBufferMode (NoShrink nl) d = forAll (NoShrink <$> genBufferMode) $ \(NoShrink mode) -> ioProperty $ withTempFile $ \_ h -> do
let ts = modData d
t = unline . map (filt (not . (`elem` "\r\n"))) $ ts
IO.hSetEncoding h enc
Expand All @@ -282,6 +282,10 @@ write_read unline filt writer reader modData
blockBuffering :: Gen IO.BufferMode
blockBuffering = IO.BlockBuffering <$> fmap (fmap $ min 4 . getPositive) arbitrary

newtype NoShrink a = NoShrink a deriving Show
instance Arbitrary a => Arbitrary (NoShrink a) where
arbitrary = NoShrink <$> arbitrary

-- Generate various Unicode space characters with high probability
arbitrarySpacyChar :: Gen Char
arbitrarySpacyChar = oneof
Expand Down

0 comments on commit eb4b004

Please sign in to comment.