2-- Module : Streamly.Benchmark.FileIO.Stream
3-- Copyright : (c) 2019 Composewell Technologies
6-- Maintainer : harendra.kumar@gmail.com
7-- Stability : experimental
10{-# LANGUAGE TemplateHaskell #-}
12{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
14module Streamly.Benchmark.FileIO.Stream
38import Data.Char (ord, chr)
39import Data.Word (Word8)
40import System.IO (Handle)
41import Prelude hiding (last, length)
43import Streamly.Streams.StreamD.Type (Step(..), GroupState)
44import Streamly.Benchmark.Inspection (hinspect)
45import qualified Streamly.Memory.Array.Types as AT
47import qualified Streamly.FileSystem.Handle as FH
48import qualified Streamly.Memory.Array as A
49import qualified Streamly.Prelude.Internal as S
50import qualified Streamly.Fold as FL
51import qualified Streamly.Data.String as SS
52import qualified Streamly.Internal as Internal
53import qualified Streamly.Streams.StreamD as D
57-- | Get the last byte from a file bytestream.
59last :: Handle -> IO (Maybe Word8)
60last = S.last . FH.read
62hinspect $ hasNoTypeClasses 'last
63hinspect $ 'last `hasNoType` ''Step
64hinspect $ 'last `hasNoType` ''AT.FlattenState
66-- assert that flattenArrays constructors are not present
67-- | Count the number of bytes in a file.
68{-# INLINE countBytes #-}
69countBytes :: Handle -> IO Int
70countBytes = S.length . FH.read
72hinspect $ hasNoTypeClasses 'countBytes
73hinspect $ 'countBytes `hasNoType` ''Step
74hinspect $ 'countBytes `hasNoType` ''AT.FlattenState
76-- | Count the number of lines in a file.
77{-# INLINE countLines #-}
78countLines :: Handle -> IO Int
81 . SS.foldLines FL.drain
85hinspect $ hasNoTypeClasses 'countLines
86hinspect $ 'countLines `hasNoType` ''Step
87hinspect $ 'countLines `hasNoType` ''AT.FlattenState
89-- | Count the number of lines in a file.
90{-# INLINE countLinesU #-}
91countLinesU :: Handle -> IO Int
94 $ SS.foldLines FL.drain
96 $ Internal.concatMapU Internal.readU (FH.readArrays inh)
98hinspect $ hasNoTypeClasses 'countLinesU
99hinspect $ 'countLinesU `hasNoType` ''Step
100hinspect $ 'countLinesU `hasNoType` ''Either
102-- | Sum the bytes in a file.
103{-# INLINE sumBytes #-}
104sumBytes :: Handle -> IO Word8
105sumBytes = S.sum . FH.read
107hinspect $ hasNoTypeClasses 'sumBytes
108hinspect $ 'sumBytes `hasNoType` ''Step
109hinspect $ 'sumBytes `hasNoType` ''AT.FlattenState
111-- | Send the file contents to /dev/null
113cat :: Handle -> Handle -> IO ()
114cat devNull inh = S.runFold (FH.write devNull) $ FH.read inh
116hinspect $ hasNoTypeClasses 'cat
117hinspect $ 'cat `hasNoType` ''Step
118hinspect $ 'cat `hasNoType` ''AT.FlattenState
120-- | Send the file contents to /dev/null
121{-# INLINE catStreamWrite #-}
122catStreamWrite :: Handle -> Handle -> IO ()
123catStreamWrite devNull inh = Internal.writeS devNull $ FH.read inh
125hinspect $ hasNoTypeClasses 'catStreamWrite
126hinspect $ 'catStreamWrite `hasNoType` ''Step
127hinspect $ 'catStreamWrite `hasNoType` ''AT.FlattenState
131copy :: Handle -> Handle -> IO ()
132copy inh outh = S.runFold (FH.write outh) (FH.read inh)
134hinspect $ hasNoTypeClasses 'copy
135hinspect $ 'copy `hasNoType` ''Step
136hinspect $ 'copy `hasNoType` ''AT.FlattenState
139{-# INLINE copyCodecChar8 #-}
140copyCodecChar8 :: Handle -> Handle -> IO ()
141copyCodecChar8 inh outh =
142 S.runFold (FH.write outh)
147hinspect $ hasNoTypeClasses 'copyCodecChar8
148hinspect $ 'copyCodecChar8 `hasNoType` ''Step
149hinspect $ 'copyCodecChar8 `hasNoType` ''AT.FlattenState
152{-# INLINE copyCodecUtf8 #-}
153copyCodecUtf8 :: Handle -> Handle -> IO ()
154copyCodecUtf8 inh outh =
155 S.runFold (FH.write outh)
160hinspect $ hasNoTypeClasses 'copyCodecUtf8
161-- hinspect $ 'copyCodecUtf8 `hasNoType` ''Step
162-- hinspect $ 'copyCodecUtf8 `hasNoType` ''AT.FlattenState
164-- | Slice in chunks of size n and get the count of chunks.
165{-# INLINE chunksOf #-}
166chunksOf :: Int -> Handle -> IO Int
168 S.length $ S.chunksOf n (AT.writeNUnsafe n) (FH.read inh)
170hinspect $ hasNoTypeClasses 'chunksOf
171hinspect $ 'chunksOf `hasNoType` ''Step
172hinspect $ 'chunksOf `hasNoType` ''AT.FlattenState
173hinspect $ 'chunksOf `hasNoType` ''GroupState
175-- This is to make sure that the concatMap in FH.read, groupsOf and foldlM'
178-- | Slice in chunks of size n and get the count of chunks.
179{-# INLINE chunksOfD #-}
180chunksOfD :: Int -> Handle -> IO Int
182 D.foldlM' (\i _ -> return $ i + 1) 0
183 $ D.groupsOf n (AT.writeNUnsafe n)
184 $ D.fromStreamK (FH.read inh)
186hinspect $ hasNoTypeClasses 'chunksOf
187hinspect $ 'chunksOf `hasNoType` ''Step
188hinspect $ 'chunksOfD `hasNoType` ''GroupState
189hinspect $ 'chunksOfD `hasNoType` ''AT.FlattenState
191-- | Lines and unlines
192{-# INLINE linesUnlinesCopy #-}
193linesUnlinesCopy :: Handle -> Handle -> IO ()
194linesUnlinesCopy inh outh =
195 S.runFold (FH.write outh)
202-- hinspect $ hasNoTypeClasses 'linesUnlinesCopy
203-- hinspect $ 'linesUnlinesCopy `hasNoType` ''Step
204-- hinspect $ 'linesUnlinesCopy `hasNoType` ''AT.FlattenState
206-- | Word, unwords and copy
207{-# INLINE wordsUnwordsCopy #-}
208wordsUnwordsCopy :: Handle -> Handle -> IO ()
209wordsUnwordsCopy inh outh =
210 S.runFold (FH.write outh)
217-- hinspect $ hasNoTypeClasses 'wordsUnwordsCopy
218-- hinspect $ 'wordsUnwordsCopy `hasNoType` ''Step
219-- hinspect $ 'wordsUnwordsCopy `hasNoType` ''AT.FlattenState
222lf = fromIntegral (ord '\n')
224toarr :: String -> A.Array Word8
225toarr = A.fromList . map (fromIntegral . ord)
227foreign import ccall unsafe "u_iswspace"
228 iswspace :: Int -> Int
230-- Code copied from base/Data.Char to INLINE it
231{-# INLINE isSpace #-}
232isSpace :: Char -> Bool
233-- isSpace includes non-breaking space
234-- The magic 0x377 isn't really that magical. As of 2014, all the codepoints
235-- at or below 0x377 have been assigned, so we shouldn't have to worry about
236-- any new spaces appearing below there. It would probably be best to
237-- use branchless ||, but currently the eqLit transformation will undo that,
238-- so we'll do it like this until there's a way around that.
240 | uc <= 0x377 = uc == 32 || uc - 0x9 <= 4 || uc == 0xa0
241 | otherwise = iswspace (ord c) /= 0
243 uc = fromIntegral (ord c) :: Word
246isSp = isSpace . chr . fromIntegral
248-- | Split on line feed.
249{-# INLINE splitOn #-}
250splitOn :: Handle -> IO Int
252 (S.length $ S.splitOn (== lf) FL.drain
253 $ FH.read inh) -- >>= print
255hinspect $ hasNoTypeClasses 'splitOn
256hinspect $ 'splitOn `hasNoType` ''Step
257hinspect $ 'splitOn `hasNoType` ''AT.FlattenState
259-- | Split suffix on line feed.
260{-# INLINE splitOnSuffix #-}
261splitOnSuffix :: Handle -> IO Int
263 (S.length $ S.splitOnSuffix (== lf) FL.drain
264 $ FH.read inh) -- >>= print
266hinspect $ hasNoTypeClasses 'splitOnSuffix
267hinspect $ 'splitOnSuffix `hasNoType` ''Step
268hinspect $ 'splitOnSuffix `hasNoType` ''AT.FlattenState
271{-# INLINE wordsBy #-}
272wordsBy :: Handle -> IO Int
274 (S.length $ S.wordsBy isSp FL.drain
275 $ FH.read inh) -- >>= print
277hinspect $ hasNoTypeClasses 'wordsBy
278hinspect $ 'wordsBy `hasNoType` ''Step
279hinspect $ 'wordsBy `hasNoType` ''AT.FlattenState
281-- | Split on a character sequence.
282{-# INLINE splitOnSeq #-}
283splitOnSeq :: String -> Handle -> IO Int
285 (S.length $ Internal.splitOnSeq (toarr str) FL.drain
286 $ FH.read inh) -- >>= print
288hinspect $ hasNoTypeClasses 'splitOnSeq
289-- hinspect $ 'splitOnSeq `hasNoType` ''Step
290-- hinspect $ 'splitOnSeq `hasNoType` ''AT.FlattenState
292-- | Split on suffix sequence.
293{-# INLINE splitOnSuffixSeq #-}
294splitOnSuffixSeq :: String -> Handle -> IO Int
295splitOnSuffixSeq str inh =
296 (S.length $ Internal.splitOnSuffixSeq (toarr str) FL.drain
297 $ FH.read inh) -- >>= print
299hinspect $ hasNoTypeClasses 'splitOnSuffixSeq
300-- hinspect $ 'splitOnSuffixSeq `hasNoType` ''Step
301-- hinspect $ 'splitOnSuffixSeq `hasNoType` ''AT.FlattenState
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list