on fe28607 help sign in
243 lines 8.5 kB history raw
1{-# OPTIONS_GHC -Wno-deprecations #-}
3-- |
4-- Module : Stream.Split
5-- Copyright : (c) 2019 Composewell Technologies
6-- License : BSD-3-Clause
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
9-- Portability : GHC
11{-# LANGUAGE CPP #-}
12{-# LANGUAGE ScopedTypeVariables #-}
14#ifdef __HADDOCK_VERSION__
15#undef INSPECTION
16#endif
18#ifdef INSPECTION
19{-# LANGUAGE TemplateHaskell #-}
20{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
21#endif
23module Stream.Split (benchmarks) where
25import Data.Char (ord)
26import Data.Word (Word8)
27import System.IO (Handle)
29import qualified Streamly.FileSystem.Handle as FH
30import qualified Streamly.Internal.Data.Array as A
31import qualified Streamly.Internal.Data.Fold as FL
32import qualified Streamly.Internal.Data.Parser as PR
33import qualified Streamly.Internal.Data.Stream.IsStream as IP
34import qualified Streamly.Internal.FileSystem.Handle as IFH
35import qualified Streamly.Internal.Unicode.Stream as IUS
36import qualified Streamly.Prelude as S
38import Gauge hiding (env)
39import Prelude hiding (last, length)
40import Streamly.Benchmark.Common
41import Streamly.Benchmark.Common.Handle
43#ifdef INSPECTION
44import Streamly.Internal.Data.Stream.StreamD.Type (Step(..))
46import qualified Streamly.Internal.Data.Array.Mut.Type as MA
47import qualified Streamly.Internal.Data.Unfold as IUF
49import Test.Inspection
50#endif
52 -------------------------------------------------------------------------------
53-- reduce with splitting transformations
54-------------------------------------------------------------------------------
56lf :: Word8
57lf = fromIntegral (ord '\n')
59toarr :: String -> A.Array Word8
60toarr = A.fromList . map (fromIntegral . ord)
62-- | Split on line feed.
63splitOn :: Handle -> IO Int
64splitOn inh =
65 (S.length $ S.splitOn (== lf) FL.drain
66 $ S.unfold FH.read inh) -- >>= print
68#ifdef INSPECTION
69inspect $ hasNoTypeClasses 'splitOn
70inspect $ 'splitOn `hasNoType` ''Step
71inspect $ 'splitOn `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
72inspect $ 'splitOn `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
73#endif
75-- | Split suffix on line feed.
76splitOnSuffix :: Handle -> IO Int
77splitOnSuffix inh =
78 (S.length $ S.splitOnSuffix (== lf) FL.drain
79 $ S.unfold FH.read inh) -- >>= print
81#ifdef INSPECTION
82inspect $ hasNoTypeClasses 'splitOnSuffix
83inspect $ 'splitOnSuffix `hasNoType` ''Step
84inspect $ 'splitOnSuffix `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
85inspect $ 'splitOnSuffix `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
86#endif
88-- | Split suffix with line feed.
89splitWithSuffix :: Handle -> IO Int
90splitWithSuffix inh =
91 (S.length $ S.splitWithSuffix (== lf) FL.drain
92 $ S.unfold FH.read inh) -- >>= print
94#ifdef INSPECTION
95inspect $ hasNoTypeClasses 'splitWithSuffix
96inspect $ 'splitWithSuffix `hasNoType` ''Step
97inspect $ 'splitWithSuffix `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
98inspect $ 'splitWithSuffix `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
99#endif
101-- | Split on line feed.
102foldManySepBy :: Handle -> IO Int
103foldManySepBy inh =
104 (S.length
105 $ IP.foldMany
106 (FL.takeEndBy_ (== lf) FL.drain)
107 (S.unfold FH.read inh)
108 ) -- >>= print
110-- | Split on line feed.
111parseManySepBy :: Handle -> IO Int
112parseManySepBy inh =
113 (S.length
114 $ IP.parseMany
115 (PR.fromFold $ FL.takeEndBy_ (== lf) FL.drain)
116 (S.unfold FH.read inh)
117 ) -- >>= print
119-- | Words by space
120wordsBy :: Handle -> IO Int
121wordsBy inh =
122 (S.length $ S.wordsBy isSp FL.drain
123 $ S.unfold FH.read inh) -- >>= print
125#ifdef INSPECTION
126inspect $ hasNoTypeClasses 'wordsBy
127inspect $ 'wordsBy `hasNoType` ''Step
128inspect $ 'wordsBy `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
129inspect $ 'wordsBy `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
130#endif
132-- | Split on a word8 sequence.
133splitOnSeq :: String -> Handle -> IO Int
134splitOnSeq str inh =
135 (S.length $ IP.splitOnSeq (toarr str) FL.drain
136 $ S.unfold FH.read inh) -- >>= print
138#ifdef INSPECTION
139-- inspect $ hasNoTypeClasses 'splitOnSeq
140-- inspect $ 'splitOnSeq `hasNoType` ''Step
141#endif
143-- | Split on a word8 sequence.
144splitOnSeq100k :: Handle -> IO Int
145splitOnSeq100k inh = do
146 arr <- A.fromStream $ S.replicate 100000 123
147 (S.length $ IP.splitOnSeq arr FL.drain
148 $ S.unfold FH.read inh) -- >>= print
150-- | Split on suffix sequence.
151splitOnSuffixSeq :: String -> Handle -> IO Int
152splitOnSuffixSeq str inh =
153 (S.length $ IP.splitOnSuffixSeq (toarr str) FL.drain
154 $ S.unfold FH.read inh) -- >>= print
156#ifdef INSPECTION
157-- inspect $ hasNoTypeClasses 'splitOnSuffixSeq
158-- inspect $ 'splitOnSuffixSeq `hasNoType` ''Step
159#endif
161-- | Split on suffix sequence.
162splitWithSuffixSeq :: String -> Handle -> IO Int
163splitWithSuffixSeq str inh =
164 S.length $ IP.splitWithSuffixSeq (toarr str) FL.drain
165 $ S.unfold FH.read inh -- >>= print
167o_1_space_reduce_read_split :: BenchEnv -> [Benchmark]
168o_1_space_reduce_read_split env =
169 [ bgroup "split"
170 [ mkBench "S.foldMany (FL.takeEndBy_ (== lf) FL.drain)" env
171 $ \inh _ -> foldManySepBy inh
172 , mkBench "S.parseMany (FL.takeEndBy_ (== lf) FL.drain)" env
173 $ \inh _ -> parseManySepBy inh
174 , mkBench "S.wordsBy isSpace FL.drain" env $ \inh _ ->
175 wordsBy inh
176 , mkBench "S.splitOn (== lf) FL.drain" env $ \inh _ ->
177 splitOn inh
178 , mkBench "S.splitOnSuffix (== lf) FL.drain" env $ \inh _ ->
179 splitOnSuffix inh
180 , mkBench "S.splitWithSuffix (== lf) FL.drain" env $ \inh _ ->
181 splitWithSuffix inh
182 , mkBench "S.splitOnSeq \"\" FL.drain" env $ \inh _ ->
183 splitOnSeq "" inh
184 , mkBench "S.splitOnSuffixSeq \"\" FL.drain" env $ \inh _ ->
185 splitOnSuffixSeq "" inh
186 , mkBench "S.splitOnSeq \"\\n\" FL.drain" env $ \inh _ ->
187 splitOnSeq "\n" inh
188 , mkBench "S.splitOnSuffixSeq \"\\n\" FL.drain" env $ \inh _ ->
189 splitOnSuffixSeq "\n" inh
190 , mkBench "S.splitOnSeq \"a\" FL.drain" env $ \inh _ ->
191 splitOnSeq "a" inh
192 , mkBench "S.splitOnSeq \"\\r\\n\" FL.drain" env $ \inh _ ->
193 splitOnSeq "\r\n" inh
194 , mkBench "S.splitOnSuffixSeq \"\\r\\n\" FL.drain" env $ \inh _ ->
195 splitOnSuffixSeq "\r\n" inh
196 , mkBench "S.splitWithSuffixSeq \"\\r\\n\" FL.drain" env $ \inh _ ->
197 splitWithSuffixSeq "\r\n" inh
198 , mkBench "S.splitOnSeq \"aa\" FL.drain" env $ \inh _ ->
199 splitOnSeq "aa" inh
200 , mkBench "S.splitOnSeq \"aaaa\" FL.drain" env $ \inh _ ->
201 splitOnSeq "aaaa" inh
202 , mkBench "S.splitOnSeq \"abcdefgh\" FL.drain" env $ \inh _ ->
203 splitOnSeq "abcdefgh" inh
204 , mkBench "S.splitOnSeq \"abcdefghi\" FL.drain" env $ \inh _ ->
205 splitOnSeq "abcdefghi" inh
206 , mkBench "S.splitOnSeq \"catcatcatcatcat\" FL.drain" env $ \inh _ ->
207 splitOnSeq "catcatcatcatcat" inh
208 , mkBench "S.splitOnSeq \"abcdefghijklmnopqrstuvwxyz\" FL.drain"
209 env $ \inh _ -> splitOnSeq "abcdefghijklmnopqrstuvwxyz" inh
210 , mkBench "S.splitOnSeq 100k long pattern"
211 env $ \inh _ -> splitOnSeq100k inh
212 , mkBenchSmall "S.splitOnSuffixSeq \"abcdefghijklmnopqrstuvwxyz\" FL.drain"
213 env $ \inh _ -> splitOnSuffixSeq "abcdefghijklmnopqrstuvwxyz" inh
214 , mkBenchSmall "S.splitWithSuffixSeq \"abcdefghijklmnopqrstuvwxyz\" FL.drain"
215 env $ \inh _ -> splitWithSuffixSeq "abcdefghijklmnopqrstuvwxyz" inh
216 ]
217 ]
219-- | Split on a character sequence.
220splitOnSeqUtf8 :: String -> Handle -> IO Int
221splitOnSeqUtf8 str inh =
222 (S.length $ IP.splitOnSeq (A.fromList str) FL.drain
223 $ IUS.decodeUtf8Arrays
224 $ IFH.getChunks inh) -- >>= print
226o_1_space_reduce_toChunks_split :: BenchEnv -> [Benchmark]
227o_1_space_reduce_toChunks_split env =
228 [ bgroup "split/toChunks"
229 [ mkBenchSmall ("S.splitOnSeqUtf8 \"abcdefgh\" FL.drain "
230 ++ ". US.decodeUtf8Arrays") env $ \inh _ ->
231 splitOnSeqUtf8 "abcdefgh" inh
232 , mkBenchSmall "S.splitOnSeqUtf8 \"abcdefghijklmnopqrstuvwxyz\" FL.drain"
233 env $ \inh _ -> splitOnSeqUtf8 "abcdefghijklmnopqrstuvwxyz" inh
234 ]
235 ]
237benchmarks :: String -> BenchEnv -> [Benchmark]
238benchmarks moduleName env =
239 [ bgroup (o_1_space_prefix moduleName) $ concat
240 [ o_1_space_reduce_read_split env
241 , o_1_space_reduce_toChunks_split env
242 ]
243 ]