on 294aa21 help sign in
666 lines 21 kB history raw
1-- |
2-- Module : Streamly.Benchmark.FileIO.Stream
3-- Copyright : (c) 2019 Composewell Technologies
4--
5-- License : BSD3
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
8-- Portability : GHC
10{-# LANGUAGE CPP #-}
11{-# LANGUAGE ScopedTypeVariables #-}
13#ifdef __HADDOCK_VERSION__
14#undef INSPECTION
15#endif
17#ifdef INSPECTION
18{-# LANGUAGE TemplateHaskell #-}
19{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
20#endif
22module Streamly.Benchmark.FileIO.Stream
23 (
24 -- * FileIO
25 last
26 , countBytes
27 , countLines
28 , countLinesU
29 , countWords
30 , sumBytes
31 , cat
32 , catStreamWrite
33 , catBracket
34 , catBracketIO
35 , catBracketStream
36 , catBracketStreamIO
37 , catOnException
38 , catOnExceptionStream
39 , catHandle
40 , catHandleStream
41 , catFinally
42 , catFinallyIO
43 , catFinallyStream
44 , catFinallyStreamIO
45 , copy
46 , linesUnlinesCopy
47 , linesUnlinesArrayWord8Copy
48 , linesUnlinesArrayCharCopy
49 -- , linesUnlinesArrayUtf8Copy
50 , wordsUnwordsCopyWord8
51 , wordsUnwordsCopy
52 , wordsUnwordsCharArrayCopy
53 , readWord8
54 , decodeLatin1
55 , copyCodecChar8
56 , copyCodecUtf8
57 , decodeUtf8Lax
58 , copyCodecUtf8Lenient
59 , chunksOfSum
60 , parseManyChunksOfSum
61 , chunksOf
62 , chunksOfD
63 , splitOn
64 , splitOnSuffix
65 , parseManySepBy
66 , wordsBy
67 , splitOnSeq
68 , splitOnSeqUtf8
69 , splitOnSuffixSeq
70 )
71where
73import Control.Exception (SomeException)
74import Data.Char (ord, chr)
75import Data.Word (Word8)
76import System.IO (Handle, hClose)
77import Prelude hiding (last, length)
79import qualified Streamly.FileSystem.Handle as FH
80import qualified Streamly.Internal.FileSystem.Handle as IFH
81import qualified Streamly.Memory.Array as A
82-- import qualified Streamly.Internal.Memory.Array as IA
83import qualified Streamly.Internal.Memory.Array.Types as AT
84import qualified Streamly.Prelude as S
85import qualified Streamly.Data.Fold as FL
86-- import qualified Streamly.Internal.Data.Fold as IFL
87import qualified Streamly.Data.Unicode.Stream as SS
88import qualified Streamly.Internal.Data.Unicode.Stream as IUS
89import qualified Streamly.Internal.Memory.Unicode.Array as IUA
90import qualified Streamly.Internal.Data.Unfold as IUF
91import qualified Streamly.Internal.Data.Parser as PR
92import qualified Streamly.Internal.Prelude as IP
93import qualified Streamly.Internal.Data.Stream.StreamD as D
95#ifdef INSPECTION
96import Foreign.Storable (Storable)
97import Streamly.Internal.Data.Stream.StreamD.Type (Step(..), GroupState)
98import Test.Inspection
99#endif
101-- | Get the last byte from a file bytestream.
102{-# INLINE last #-}
103last :: Handle -> IO (Maybe Word8)
104last = S.last . S.unfold FH.read
106#ifdef INSPECTION
107inspect $ hasNoTypeClasses 'last
108inspect $ 'last `hasNoType` ''Step
109inspect $ 'last `hasNoType` ''AT.FlattenState
110inspect $ 'last `hasNoType` ''D.ConcatMapUState
111#endif
113-- assert that flattenArrays constructors are not present
114-- | Count the number of bytes in a file.
115{-# INLINE countBytes #-}
116countBytes :: Handle -> IO Int
117countBytes = S.length . S.unfold FH.read
119#ifdef INSPECTION
120inspect $ hasNoTypeClasses 'countBytes
121inspect $ 'countBytes `hasNoType` ''Step
122inspect $ 'countBytes `hasNoType` ''AT.FlattenState
123inspect $ 'countBytes `hasNoType` ''D.ConcatMapUState
124#endif
126-- | Count the number of lines in a file.
127{-# INLINE countLines #-}
128countLines :: Handle -> IO Int
129countLines =
130 S.length
131 . IUS.lines FL.drain
132 . SS.decodeLatin1
133 . S.unfold FH.read
135#ifdef INSPECTION
136inspect $ hasNoTypeClasses 'countLines
137inspect $ 'countLines `hasNoType` ''Step
138inspect $ 'countLines `hasNoType` ''AT.FlattenState
139inspect $ 'countLines `hasNoType` ''D.ConcatMapUState
140#endif
142-- | Count the number of words in a file.
143{-# INLINE countWords #-}
144countWords :: Handle -> IO Int
145countWords =
146 S.length
147 . IUS.words FL.drain
148 . SS.decodeLatin1
149 . S.unfold FH.read
151#ifdef INSPECTION
152inspect $ hasNoTypeClasses 'countWords
153-- inspect $ 'countWords `hasNoType` ''Step
154-- inspect $ 'countWords `hasNoType` ''D.ConcatMapUState
155#endif
157-- | Count the number of lines in a file.
158{-# INLINE countLinesU #-}
159countLinesU :: Handle -> IO Int
160countLinesU inh =
161 S.length
162 $ IUS.lines FL.drain
163 $ SS.decodeLatin1
164 $ S.concatUnfold A.read (IFH.toChunks inh)
166#ifdef INSPECTION
167inspect $ hasNoTypeClasses 'countLinesU
168inspect $ 'countLinesU `hasNoType` ''Step
169inspect $ 'countLinesU `hasNoType` ''D.ConcatMapUState
170#endif
172-- | Sum the bytes in a file.
173{-# INLINE sumBytes #-}
174sumBytes :: Handle -> IO Word8
175sumBytes = S.sum . S.unfold FH.read
177#ifdef INSPECTION
178inspect $ hasNoTypeClasses 'sumBytes
179inspect $ 'sumBytes `hasNoType` ''Step
180inspect $ 'sumBytes `hasNoType` ''AT.FlattenState
181inspect $ 'sumBytes `hasNoType` ''D.ConcatMapUState
182#endif
184-- | Send the file contents to /dev/null
185{-# INLINE cat #-}
186cat :: Handle -> Handle -> IO ()
187cat devNull inh = S.fold (FH.write devNull) $ S.unfold FH.read inh
189#ifdef INSPECTION
190inspect $ hasNoTypeClasses 'cat
191inspect $ 'cat `hasNoType` ''Step
192inspect $ 'cat `hasNoType` ''AT.FlattenState
193inspect $ 'cat `hasNoType` ''D.ConcatMapUState
194#endif
196-- | Send the file contents to /dev/null
197{-# INLINE catStreamWrite #-}
198catStreamWrite :: Handle -> Handle -> IO ()
199catStreamWrite devNull inh = IFH.fromBytes devNull $ S.unfold FH.read inh
201#ifdef INSPECTION
202inspect $ hasNoTypeClasses 'catStreamWrite
203inspect $ 'catStreamWrite `hasNoType` ''Step
204inspect $ 'catStreamWrite `hasNoType` ''AT.FlattenState
205inspect $ 'catStreamWrite `hasNoType` ''D.ConcatMapUState
206#endif
208-- | Send the file contents to /dev/null with exception handling
209{-# INLINE catBracket #-}
210catBracket :: Handle -> Handle -> IO ()
211catBracket devNull inh =
212 let readEx = IUF.bracket return (\_ -> hClose inh) FH.read
213 in S.fold (FH.write devNull) $ S.unfold readEx inh
215#ifdef INSPECTION
216inspect $ hasNoTypeClasses 'catBracket
217-- inspect $ 'catBracket `hasNoType` ''Step
218-- inspect $ 'catBracket `hasNoType` ''AT.FlattenState
219-- inspect $ 'catBracket `hasNoType` ''D.ConcatMapUState
220#endif
222{-# INLINE catBracketIO #-}
223catBracketIO :: Handle -> Handle -> IO ()
224catBracketIO devNull inh =
225 let readEx = IUF.bracketIO return (\_ -> hClose inh) FH.read
226 in S.fold (FH.write devNull) $ S.unfold readEx inh
228-- | Send the file contents to /dev/null with exception handling
229{-# INLINE catBracketStream #-}
230catBracketStream :: Handle -> Handle -> IO ()
231catBracketStream devNull inh =
232 let readEx = S.bracket (return ()) (\_ -> hClose inh)
233 (\_ -> IFH.toBytes inh)
234 in IFH.fromBytes devNull $ readEx
236#ifdef INSPECTION
237inspect $ hasNoTypeClasses 'catBracketStream
238-- inspect $ 'catBracketStream `hasNoType` ''Step
239#endif
241{-# INLINE catBracketStreamIO #-}
242catBracketStreamIO :: Handle -> Handle -> IO ()
243catBracketStreamIO devNull inh =
244 let readEx = IP.bracketIO (return ()) (\_ -> hClose inh)
245 (\_ -> IFH.toBytes inh)
246 in IFH.fromBytes devNull $ readEx
248-- | Send the file contents to /dev/null with exception handling
249{-# INLINE catOnException #-}
250catOnException :: Handle -> Handle -> IO ()
251catOnException devNull inh =
252 let readEx = IUF.onException (\_ -> hClose inh) FH.read
253 in S.fold (FH.write devNull) $ S.unfold readEx inh
255#ifdef INSPECTION
256inspect $ hasNoTypeClasses 'catOnException
257-- inspect $ 'catOnException `hasNoType` ''Step
258-- inspect $ 'catOnException `hasNoType` ''AT.FlattenState
259-- inspect $ 'catOnException `hasNoType` ''D.ConcatMapUState
260#endif
262-- | Send the file contents to /dev/null with exception handling
263{-# INLINE catOnExceptionStream #-}
264catOnExceptionStream :: Handle -> Handle -> IO ()
265catOnExceptionStream devNull inh =
266 let readEx = S.onException (hClose inh) (S.unfold FH.read inh)
267 in S.fold (FH.write devNull) $ readEx
269-- | Send the file contents to /dev/null with exception handling
270{-# INLINE catFinally #-}
271catFinally :: Handle -> Handle -> IO ()
272catFinally devNull inh =
273 let readEx = IUF.finally (\_ -> hClose inh) FH.read
274 in S.fold (FH.write devNull) $ S.unfold readEx inh
276#ifdef INSPECTION
277inspect $ hasNoTypeClasses 'catFinally
278-- inspect $ 'catFinally `hasNoType` ''Step
279-- inspect $ 'catFinally `hasNoType` ''AT.FlattenState
280-- inspect $ 'catFinally `hasNoType` ''D.ConcatMapUState
281#endif
283{-# INLINE catFinallyIO #-}
284catFinallyIO :: Handle -> Handle -> IO ()
285catFinallyIO devNull inh =
286 let readEx = IUF.finallyIO (\_ -> hClose inh) FH.read
287 in S.fold (FH.write devNull) $ S.unfold readEx inh
289-- | Send the file contents to /dev/null with exception handling
290{-# INLINE catFinallyStream #-}
291catFinallyStream :: Handle -> Handle -> IO ()
292catFinallyStream devNull inh =
293 let readEx = S.finally (hClose inh) (S.unfold FH.read inh)
294 in S.fold (FH.write devNull) readEx
296{-# INLINE catFinallyStreamIO #-}
297catFinallyStreamIO :: Handle -> Handle -> IO ()
298catFinallyStreamIO devNull inh =
299 let readEx = IP.finallyIO (hClose inh) (S.unfold FH.read inh)
300 in S.fold (FH.write devNull) readEx
302-- | Send the file contents to /dev/null with exception handling
303{-# INLINE catHandle #-}
304catHandle :: Handle -> Handle -> IO ()
305catHandle devNull inh =
306 let handler (_e :: SomeException) = hClose inh >> return 10
307 readEx = IUF.handle (IUF.singletonM handler) FH.read
308 in S.fold (FH.write devNull) $ S.unfold readEx inh
310#ifdef INSPECTION
311inspect $ hasNoTypeClasses 'catHandle
312-- inspect $ 'catHandle `hasNoType` ''Step
313-- inspect $ 'catHandle `hasNoType` ''AT.FlattenState
314-- inspect $ 'catHandle `hasNoType` ''D.ConcatMapUState
315#endif
317-- | Send the file contents to /dev/null with exception handling
318{-# INLINE catHandleStream #-}
319catHandleStream :: Handle -> Handle -> IO ()
320catHandleStream devNull inh =
321 let handler (_e :: SomeException) = S.yieldM (hClose inh >> return 10)
322 readEx = S.handle handler (S.unfold FH.read inh)
323 in S.fold (FH.write devNull) $ readEx
325-- | Copy file
326{-# INLINE copy #-}
327copy :: Handle -> Handle -> IO ()
328copy inh outh = S.fold (FH.write outh) (S.unfold FH.read inh)
330#ifdef INSPECTION
331inspect $ hasNoTypeClasses 'copy
332inspect $ 'copy `hasNoType` ''Step
333inspect $ 'copy `hasNoType` ''AT.FlattenState
334inspect $ 'copy `hasNoType` ''D.ConcatMapUState
335#endif
337{-# INLINE readWord8 #-}
338readWord8 :: Handle -> IO ()
339readWord8 inh = S.drain $ S.unfold FH.read inh
341{-# INLINE decodeLatin1 #-}
342decodeLatin1 :: Handle -> IO ()
343decodeLatin1 inh =
344 S.drain
345 $ SS.decodeLatin1
346 $ S.unfold FH.read inh
348-- | Copy file
349{-# INLINE copyCodecChar8 #-}
350copyCodecChar8 :: Handle -> Handle -> IO ()
351copyCodecChar8 inh outh =
352 S.fold (FH.write outh)
353 $ SS.encodeLatin1
354 $ SS.decodeLatin1
355 $ S.unfold FH.read inh
357#ifdef INSPECTION
358inspect $ hasNoTypeClasses 'copyCodecChar8
359inspect $ 'copyCodecChar8 `hasNoType` ''Step
360inspect $ 'copyCodecChar8 `hasNoType` ''AT.FlattenState
361inspect $ 'copyCodecChar8 `hasNoType` ''D.ConcatMapUState
362#endif
364{-# INLINE decodeUtf8Lax #-}
365decodeUtf8Lax :: Handle -> IO ()
366decodeUtf8Lax inh =
367 S.drain
368 $ SS.decodeUtf8Lax
369 $ S.unfold FH.read inh
371#ifdef INSPECTION
372inspect $ hasNoTypeClasses 'decodeUtf8Lax
373-- inspect $ 'decodeUtf8Lax `hasNoType` ''Step
374-- inspect $ 'decodeUtf8Lax `hasNoType` ''AT.FlattenState
375-- inspect $ 'decodeUtf8Lax `hasNoType` ''D.ConcatMapUState
376#endif
378-- | Copy file
379{-# INLINE copyCodecUtf8 #-}
380copyCodecUtf8 :: Handle -> Handle -> IO ()
381copyCodecUtf8 inh outh =
382 S.fold (FH.write outh)
383 $ SS.encodeUtf8
384 $ SS.decodeUtf8
385 $ S.unfold FH.read inh
387#ifdef INSPECTION
388inspect $ hasNoTypeClasses 'copyCodecUtf8
389-- inspect $ 'copyCodecUtf8 `hasNoType` ''Step
390-- inspect $ 'copyCodecUtf8 `hasNoType` ''AT.FlattenState
391-- inspect $ 'copyCodecUtf8 `hasNoType` ''D.ConcatMapUState
392#endif
394-- | Copy file
395{-# INLINE copyCodecUtf8Lenient #-}
396copyCodecUtf8Lenient :: Handle -> Handle -> IO ()
397copyCodecUtf8Lenient inh outh =
398 S.fold (FH.write outh)
399 $ SS.encodeUtf8
400 $ SS.decodeUtf8Lax
401 $ S.unfold FH.read inh
403#ifdef INSPECTION
404inspect $ hasNoTypeClasses 'copyCodecUtf8Lenient
405-- inspect $ 'copyCodecUtf8Lenient `hasNoType` ''Step
406-- inspect $ 'copyCodecUtf8Lenient `hasNoType` ''AT.FlattenState
407-- inspect $ 'copyCodecUtf8Lenient `hasNoType` ''D.ConcatMapUState
408#endif
410{-# INLINE chunksOfSum #-}
411chunksOfSum :: Int -> Handle -> IO Int
412chunksOfSum n inh = S.length $ S.chunksOf n FL.sum (S.unfold FH.read inh)
414-- | Slice in chunks of size n and get the count of chunks.
415{-# INLINE chunksOf #-}
416chunksOf :: Int -> Handle -> IO Int
417chunksOf n inh =
418 -- writeNUnsafe gives 2.5x boost here over writeN.
419 S.length $ S.chunksOf n (AT.writeNUnsafe n) (S.unfold FH.read inh)
421#ifdef INSPECTION
422inspect $ hasNoTypeClasses 'chunksOf
423inspect $ 'chunksOf `hasNoType` ''Step
424inspect $ 'chunksOf `hasNoType` ''AT.FlattenState
425inspect $ 'chunksOf `hasNoType` ''D.ConcatMapUState
426inspect $ 'chunksOf `hasNoType` ''GroupState
427#endif
429-- This is to make sure that the concatMap in FH.read, groupsOf and foldlM'
430-- together can fuse.
431--
432-- | Slice in chunks of size n and get the count of chunks.
433{-# INLINE chunksOfD #-}
434chunksOfD :: Int -> Handle -> IO Int
435chunksOfD n inh =
436 D.foldlM' (\i _ -> return $ i + 1) 0
437 $ D.groupsOf n (AT.writeNUnsafe n)
438 $ D.fromStreamK (S.unfold FH.read inh)
440#ifdef INSPECTION
441inspect $ hasNoTypeClasses 'chunksOf
442inspect $ 'chunksOf `hasNoType` ''Step
443inspect $ 'chunksOfD `hasNoType` ''GroupState
444inspect $ 'chunksOfD `hasNoType` ''AT.FlattenState
445inspect $ 'chunksOfD `hasNoType` ''D.ConcatMapUState
446#endif
448{-# INLINE parseManyChunksOfSum #-}
449parseManyChunksOfSum :: Int -> Handle -> IO Int
450parseManyChunksOfSum n inh =
451 S.length $ IP.parseMany (PR.take n FL.sum) (S.unfold FH.read inh)
453{-# INLINE linesUnlinesCopy #-}
454linesUnlinesCopy :: Handle -> Handle -> IO ()
455linesUnlinesCopy inh outh =
456 S.fold (FH.write outh)
457 $ SS.encodeLatin1
458 $ IUS.unlines IUF.fromList
459 $ S.splitOnSuffix (== '\n') FL.toList
460 $ SS.decodeLatin1
461 $ S.unfold FH.read inh
463{-# INLINE linesUnlinesArrayWord8Copy #-}
464linesUnlinesArrayWord8Copy :: Handle -> Handle -> IO ()
465linesUnlinesArrayWord8Copy inh outh =
466 S.fold (FH.write outh)
467 $ IP.interposeSuffix 10 A.read
468 $ S.splitOnSuffix (== 10) A.write
469 $ S.unfold FH.read inh
471-- XXX splitSuffixOn requires -funfolding-use-threshold=150 for better fusion
472-- | Lines and unlines
473{-# INLINE linesUnlinesArrayCharCopy #-}
474linesUnlinesArrayCharCopy :: Handle -> Handle -> IO ()
475linesUnlinesArrayCharCopy inh outh =
476 S.fold (FH.write outh)
477 $ SS.encodeLatin1
478 $ IUA.unlines
479 $ IUA.lines
480 $ SS.decodeLatin1
481 $ S.unfold FH.read inh
483#ifdef INSPECTION
484inspect $ hasNoTypeClassesExcept 'linesUnlinesArrayCharCopy [''Storable]
485-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''Step
486-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''AT.FlattenState
487-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''D.ConcatMapUState
488#endif
490-- XXX to write this we need to be able to map decodeUtf8 on the A.read fold.
491-- For that we have to write decodeUtf8 as a Pipe.
492{-
493{-# INLINE linesUnlinesArrayUtf8Copy #-}
494linesUnlinesArrayUtf8Copy :: Handle -> Handle -> IO ()
495linesUnlinesArrayUtf8Copy inh outh =
496 S.fold (FH.write outh)
497 $ SS.encodeLatin1
498 $ IP.intercalate (A.fromList [10]) (pipe SS.decodeUtf8P A.read)
499 $ S.splitOnSuffix (== '\n') (IFL.lmap SS.encodeUtf8 A.write)
500 $ SS.decodeLatin1
501 $ S.unfold FH.read inh
502-}
504foreign import ccall unsafe "u_iswspace"
505 iswspace :: Int -> Int
507-- Code copied from base/Data.Char to INLINE it
508{-# INLINE isSpace #-}
509isSpace :: Char -> Bool
510-- isSpace includes non-breaking space
511-- The magic 0x377 isn't really that magical. As of 2014, all the codepoints
512-- at or below 0x377 have been assigned, so we shouldn't have to worry about
513-- any new spaces appearing below there. It would probably be best to
514-- use branchless ||, but currently the eqLit transformation will undo that,
515-- so we'll do it like this until there's a way around that.
516isSpace c
517 | uc <= 0x377 = uc == 32 || uc - 0x9 <= 4 || uc == 0xa0
518 | otherwise = iswspace (ord c) /= 0
519 where
520 uc = fromIntegral (ord c) :: Word
522{-# INLINE isSp #-}
523isSp :: Word8 -> Bool
524isSp = isSpace . chr . fromIntegral
526-- | Word, unwords and copy
527{-# INLINE wordsUnwordsCopyWord8 #-}
528wordsUnwordsCopyWord8 :: Handle -> Handle -> IO ()
529wordsUnwordsCopyWord8 inh outh =
530 S.fold (FH.write outh)
531 $ IP.interposeSuffix 32 IUF.fromList
532 $ S.wordsBy isSp FL.toList
533 $ S.unfold FH.read inh
535#ifdef INSPECTION
536inspect $ hasNoTypeClasses 'wordsUnwordsCopyWord8
537-- inspect $ 'wordsUnwordsCopyWord8 `hasNoType` ''Step
538-- inspect $ 'wordsUnwordsCopyWord8 `hasNoType` ''D.ConcatMapUState
539#endif
541-- | Word, unwords and copy
542{-# INLINE wordsUnwordsCopy #-}
543wordsUnwordsCopy :: Handle -> Handle -> IO ()
544wordsUnwordsCopy inh outh =
545 S.fold (FH.write outh)
546 $ SS.encodeLatin1
547 $ IUS.unwords IUF.fromList
548 -- XXX This pipeline does not fuse with wordsBy but fuses with splitOn
549 -- with -funfolding-use-threshold=300. With wordsBy it does not fuse
550 -- even with high limits for inlining and spec-constr ghc options. With
551 -- -funfolding-use-threshold=400 it performs pretty well and there
552 -- is no evidence in the core that a join point involving Step
553 -- constructors is not getting inlined. Not being able to fuse at all in
554 -- this case could be an unknown issue, need more investigation.
555 $ S.wordsBy isSpace FL.toList
556 -- -- $ S.splitOn isSpace FL.toList
557 $ SS.decodeLatin1
558 $ S.unfold FH.read inh
560#ifdef INSPECTION
561-- inspect $ hasNoTypeClasses 'wordsUnwordsCopy
562-- inspect $ 'wordsUnwordsCopy `hasNoType` ''Step
563-- inspect $ 'wordsUnwordsCopy `hasNoType` ''AT.FlattenState
564-- inspect $ 'wordsUnwordsCopy `hasNoType` ''D.ConcatMapUState
565#endif
567{-# INLINE wordsUnwordsCharArrayCopy #-}
568wordsUnwordsCharArrayCopy :: Handle -> Handle -> IO ()
569wordsUnwordsCharArrayCopy inh outh =
570 S.fold (FH.write outh)
571 $ SS.encodeLatin1
572 $ IUA.unwords
573 $ IUA.words
574 $ SS.decodeLatin1
575 $ S.unfold FH.read inh
577lf :: Word8
578lf = fromIntegral (ord '\n')
580toarr :: String -> A.Array Word8
581toarr = A.fromList . map (fromIntegral . ord)
583-- | Split on line feed.
584{-# INLINE splitOn #-}
585splitOn :: Handle -> IO Int
586splitOn inh =
587 (S.length $ S.splitOn (== lf) FL.drain
588 $ S.unfold FH.read inh) -- >>= print
590#ifdef INSPECTION
591inspect $ hasNoTypeClasses 'splitOn
592inspect $ 'splitOn `hasNoType` ''Step
593inspect $ 'splitOn `hasNoType` ''AT.FlattenState
594inspect $ 'splitOn `hasNoType` ''D.ConcatMapUState
595#endif
597-- | Split suffix on line feed.
598{-# INLINE splitOnSuffix #-}
599splitOnSuffix :: Handle -> IO Int
600splitOnSuffix inh =
601 (S.length $ S.splitOnSuffix (== lf) FL.drain
602 $ S.unfold FH.read inh) -- >>= print
604#ifdef INSPECTION
605inspect $ hasNoTypeClasses 'splitOnSuffix
606inspect $ 'splitOnSuffix `hasNoType` ''Step
607inspect $ 'splitOnSuffix `hasNoType` ''AT.FlattenState
608inspect $ 'splitOnSuffix `hasNoType` ''D.ConcatMapUState
609#endif
611-- | Split on line feed.
612{-# INLINE parseManySepBy #-}
613parseManySepBy :: Handle -> IO Int
614parseManySepBy inh =
615 (S.length $ IP.parseMany (PR.sliceSepBy (== lf) FL.drain)
616 (S.unfold FH.read inh)) -- >>= print
618-- | Words by space
619{-# INLINE wordsBy #-}
620wordsBy :: Handle -> IO Int
621wordsBy inh =
622 (S.length $ S.wordsBy isSp FL.drain
623 $ S.unfold FH.read inh) -- >>= print
625#ifdef INSPECTION
626inspect $ hasNoTypeClasses 'wordsBy
627inspect $ 'wordsBy `hasNoType` ''Step
628inspect $ 'wordsBy `hasNoType` ''AT.FlattenState
629inspect $ 'wordsBy `hasNoType` ''D.ConcatMapUState
630#endif
632-- | Split on a word8 sequence.
633{-# INLINE splitOnSeq #-}
634splitOnSeq :: String -> Handle -> IO Int
635splitOnSeq str inh =
636 (S.length $ IP.splitOnSeq (toarr str) FL.drain
637 $ S.unfold FH.read inh) -- >>= print
639#ifdef INSPECTION
640-- inspect $ hasNoTypeClasses 'splitOnSeq
641-- inspect $ 'splitOnSeq `hasNoType` ''Step
642-- inspect $ 'splitOnSeq `hasNoType` ''AT.FlattenState
643-- inspect $ 'splitOnSeq `hasNoType` ''D.ConcatMapUState
644#endif
646-- | Split on a character sequence.
647{-# INLINE splitOnSeqUtf8 #-}
648splitOnSeqUtf8 :: String -> Handle -> IO Int
649splitOnSeqUtf8 str inh =
650 (S.length $ IP.splitOnSeq (A.fromList str) FL.drain
651 $ IUS.decodeUtf8ArraysLenient
652 $ IFH.toChunks inh) -- >>= print
654-- | Split on suffix sequence.
655{-# INLINE splitOnSuffixSeq #-}
656splitOnSuffixSeq :: String -> Handle -> IO Int
657splitOnSuffixSeq str inh =
658 (S.length $ IP.splitOnSuffixSeq (toarr str) FL.drain
659 $ S.unfold FH.read inh) -- >>= print
661#ifdef INSPECTION
662-- inspect $ hasNoTypeClasses 'splitOnSuffixSeq
663-- inspect $ 'splitOnSuffixSeq `hasNoType` ''Step
664-- inspect $ 'splitOnSuffixSeq `hasNoType` ''AT.FlattenState
665-- inspect $ 'splitOnSuffixSeq `hasNoType` ''D.ConcatMapUState
666#endif