1{-# OPTIONS_GHC -Wno-deprecations #-}
4-- Module : Streamly.Unicode.Stream
5-- Copyright : (c) 2019 Composewell Technologies
6-- License : BSD-3-Clause
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
12{-# LANGUAGE ScopedTypeVariables #-}
14#ifdef __HADDOCK_VERSION__
19{-# LANGUAGE TemplateHaskell #-}
20{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
23import Streamly.Data.Stream (Stream)
24import Streamly.Data.Fold (Fold)
25import Prelude hiding (last, length)
26import System.IO (Handle)
28import qualified Streamly.Data.Array as Array
29import qualified Streamly.Data.Fold as Fold
30import qualified Streamly.Internal.Data.Stream as Stream
31import qualified Streamly.Internal.Data.Unfold as Unfold
32import qualified Streamly.Internal.FileSystem.Handle as Handle
33import qualified Streamly.Internal.Unicode.Array as UnicodeArr
34import qualified Streamly.Internal.Unicode.Stream as Unicode
36import Gauge hiding (env)
37import Streamly.Benchmark.Common
38import Streamly.Benchmark.Common.Handle
41import Streamly.Internal.Data.Unbox (Unbox)
42import Streamly.Internal.Data.Stream (Step(..))
43import qualified Streamly.Internal.Data.Fold as Fold
44import qualified Streamly.Internal.Data.Tuple.Strict as Strict
45import qualified Streamly.Internal.Data.Array as Array
51moduleName = "Unicode.Stream"
54{-# NOINLINE copyCodecUtf8ArraysLenient #-}
55copyCodecUtf8ArraysLenient :: Handle -> Handle -> IO ()
56copyCodecUtf8ArraysLenient inh outh =
57 Stream.fold (Handle.write outh)
59 $ Unicode.decodeUtf8Chunks
60 $ Handle.readChunks inh
63inspect $ hasNoTypeClasses 'copyCodecUtf8ArraysLenient
64-- inspect $ 'copyCodecUtf8ArraysLenient `hasNoType` ''Step
67o_1_space_decode_encode_chunked :: BenchEnv -> [Benchmark]
68o_1_space_decode_encode_chunked env =
69 [ bgroup "decode-encode/toChunks"
71 mkBenchSmall "encodeUtf8' . decodeUtf8Arrays" env $ \inH outH ->
72 copyCodecUtf8ArraysLenient inH outH
76-------------------------------------------------------------------------------
77-- copy with group/ungroup transformations
78-------------------------------------------------------------------------------
80{-# INLINE splitOnSuffix #-}
83 => (a -> Bool) -> Fold m a b -> Stream m a -> Stream m b
84splitOnSuffix predicate f = Stream.foldMany (Fold.takeEndBy_ predicate f)
86{-# NOINLINE linesUnlinesCopy #-}
87linesUnlinesCopy :: Handle -> Handle -> IO ()
88linesUnlinesCopy inh outh =
89 Stream.fold (Handle.write outh)
90 $ Unicode.encodeLatin1'
91 $ Unicode.unlines Unfold.fromList
92 $ splitOnSuffix (== '\n') Fold.toList
93 $ Unicode.decodeLatin1
94 $ Stream.unfold Handle.reader inh
96{-# NOINLINE linesUnlinesArrayWord8Copy #-}
97linesUnlinesArrayWord8Copy :: Handle -> Handle -> IO ()
98linesUnlinesArrayWord8Copy inh outh =
99 Stream.fold (Handle.write outh)
100 $ Stream.interposeSuffix 10 Array.reader
101 $ splitOnSuffix (== 10) Array.write
102 $ Stream.unfold Handle.reader inh
104-- XXX splitSuffixOn requires -funfolding-use-threshold=150 for better fusion
105-- | Lines and unlines
106{-# NOINLINE linesUnlinesArrayCharCopy #-}
107linesUnlinesArrayCharCopy :: Handle -> Handle -> IO ()
108linesUnlinesArrayCharCopy inh outh =
109 Stream.fold (Handle.write outh)
110 $ Unicode.encodeLatin1'
113 $ Unicode.decodeLatin1
114 $ Stream.unfold Handle.reader inh
117inspect $ hasNoTypeClassesExcept 'linesUnlinesArrayCharCopy [''Unbox]
118-- inspect $ 'linesUnlinesArrayCharCopy `hasNoType` ''Step
121-- XXX to write this we need to be able to map decodeUtf8 on the Array.read fold.
122-- For that we have to write decodeUtf8 as a Pipe.
124{-# INLINE linesUnlinesArrayUtf8Copy #-}
125linesUnlinesArrayUtf8Copy :: Handle -> Handle -> IO ()
126linesUnlinesArrayUtf8Copy inh outh =
127 Stream.fold (Handle.write outh)
128 $ Unicode.encodeLatin1'
129 $ Stream.intercalate (Array.fromList [10]) (pipe Unicode.decodeUtf8P Array.read)
130 $ Stream.splitOnSuffix (== '\n') (IFold.map Unicode.encodeUtf8' Array.write)
131 $ Unicode.decodeLatin1
132 $ Stream.unfold Handle.read inh
135-- | Word, unwords and copy
136{-# NOINLINE wordsUnwordsCopyWord8 #-}
137wordsUnwordsCopyWord8 :: Handle -> Handle -> IO ()
138wordsUnwordsCopyWord8 inh outh =
139 Stream.fold (Handle.write outh)
140 $ Stream.interposeSuffix 32 Unfold.fromList
141 $ Stream.wordsBy isSp Fold.toList
142 $ Stream.unfold Handle.reader inh
145inspect $ hasNoTypeClasses 'wordsUnwordsCopyWord8
146-- inspect $ 'wordsUnwordsCopyWord8 `hasNoType` ''Step
149-- | Word, unwords and copy
150{-# NOINLINE wordsUnwordsCopy #-}
151wordsUnwordsCopy :: Handle -> Handle -> IO ()
152wordsUnwordsCopy inh outh =
153 Stream.fold (Handle.write outh)
154 $ Unicode.encodeLatin1'
155 $ Unicode.unwords Unfold.fromList
156 -- XXX This pipeline does not fuse with wordsBy but fuses with splitOn
157 -- with -funfolding-use-threshold=300. With wordsBy it does not fuse
158 -- even with high limits for inlining and spec-constr ghc options. With
159 -- -funfolding-use-threshold=400 it performs pretty well and there
160 -- is no evidence in the core that a join point involving Step
161 -- constructors is not getting inlined. Not being able to fuse at all in
162 -- this case could be an unknown issue, need more investigation.
163 $ Stream.wordsBy isSpace Fold.toList
164 -- -- $ Stream.splitOn isSpace Fold.toList
165 $ Unicode.decodeLatin1
166 $ Stream.unfold Handle.reader inh
169-- inspect $ hasNoTypeClasses 'wordsUnwordsCopy
170-- inspect $ 'wordsUnwordsCopy `hasNoType` ''Step
173{-# NOINLINE wordsUnwordsCharArrayCopy #-}
174wordsUnwordsCharArrayCopy :: Handle -> Handle -> IO ()
175wordsUnwordsCharArrayCopy inh outh =
176 Stream.fold (Handle.write outh)
177 $ Unicode.encodeLatin1'
180 $ Unicode.decodeLatin1
181 $ Stream.unfold Handle.reader inh
183o_1_space_copy_read_group_ungroup :: BenchEnv -> [Benchmark]
184o_1_space_copy_read_group_ungroup env =
185 [ bgroup "ungroup-group"
186 [ mkBenchSmall "unlines . splitOnSuffix ([Word8])" env
187 $ \inh outh -> linesUnlinesCopy inh outh
188 , mkBenchSmall "interposeSuffix . splitOnSuffix (Array Word8)" env
189 $ \inh outh -> linesUnlinesArrayWord8Copy inh outh
190 , mkBenchSmall "UnicodeArr.unlines . UnicodeArr.lines (Array Char)" env
191 $ \inh outh -> linesUnlinesArrayCharCopy inh outh
193 , mkBenchSmall "interposeSuffix . wordsBy ([Word8])" env
194 $ \inh outh -> wordsUnwordsCopyWord8 inh outh
195 , mkBenchSmall "unwords . wordsBy ([Char])" env
196 $ \inh outh -> wordsUnwordsCopy inh outh
197 , mkBenchSmall "UnicodeArr.unwords . UnicodeArr.words (Array Char)" env
198 $ \inh outh -> wordsUnwordsCharArrayCopy inh outh
202-------------------------------------------------------------------------------
204-------------------------------------------------------------------------------
206-- | Copy file (encodeLatin1')
207{-# NOINLINE copyStreamLatin1' #-}
208copyStreamLatin1' :: Handle -> Handle -> IO ()
209copyStreamLatin1' inh outh =
210 Stream.fold (Handle.write outh)
211 $ Unicode.encodeLatin1'
212 $ Unicode.decodeLatin1
213 $ Stream.unfold Handle.reader inh
216inspect $ hasNoTypeClasses 'copyStreamLatin1'
217inspect $ 'copyStreamLatin1' `hasNoType` ''Step
218inspect $ 'copyStreamLatin1' `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.many
220inspect $ 'copyStreamLatin1' `hasNoType` ''Fold.Step
221inspect $ 'copyStreamLatin1' `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
222 -- Handle.read/Array.read
223inspect $ 'copyStreamLatin1' `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
226-- | Copy file (encodeLatin1)
227{-# NOINLINE copyStreamLatin1 #-}
228copyStreamLatin1 :: Handle -> Handle -> IO ()
229copyStreamLatin1 inh outh =
230 Stream.fold (Handle.write outh)
231 $ Unicode.encodeLatin1
232 $ Unicode.decodeLatin1
233 $ Stream.unfold Handle.reader inh
236inspect $ hasNoTypeClasses 'copyStreamLatin1
237inspect $ 'copyStreamLatin1 `hasNoType` ''Step
238inspect $ 'copyStreamLatin1 `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.many
240inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.ManyState
241inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.Step
242inspect $ 'copyStreamLatin1 `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
243 -- Handle.read/Array.read
244inspect $ 'copyStreamLatin1 `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
248_copyStreamUtf8' :: Handle -> Handle -> IO ()
249_copyStreamUtf8' inh outh =
250 Stream.fold (Handle.write outh)
251 $ Unicode.encodeUtf8'
252 $ Unicode.decodeUtf8'
253 $ Stream.unfold Handle.reader inh
256inspect $ hasNoTypeClasses '_copyStreamUtf8'
257-- inspect $ '_copyStreamUtf8 `hasNoType` ''Step
258-- inspect $ '_copyStreamUtf8 `hasNoType` ''Array.FlattenState
259-- inspect $ '_copyStreamUtf8 `hasNoType` ''D.ConcatMapUState
263{-# NOINLINE copyStreamUtf8 #-}
264copyStreamUtf8 :: Handle -> Handle -> IO ()
265copyStreamUtf8 inh outh =
266 Stream.fold (Handle.write outh)
269 $ Stream.unfold Handle.reader inh
272inspect $ hasNoTypeClasses 'copyStreamUtf8
273-- inspect $ 'copyStreamUtf8Lax `hasNoType` ''Step
274-- inspect $ 'copyStreamUtf8Lax `hasNoType` ''Array.FlattenState
275-- inspect $ 'copyStreamUtf8Lax `hasNoType` ''D.ConcatMapUState
278{-# NOINLINE _copyStreamUtf8'Fold #-}
279_copyStreamUtf8'Fold :: Handle -> Handle -> IO ()
280_copyStreamUtf8'Fold inh outh =
281 Stream.fold (Handle.write outh)
283 $ Stream.foldMany Unicode.writeCharUtf8'
284 $ Stream.unfold Handle.reader inh
286{-# NOINLINE _copyStreamUtf8Parser #-}
287_copyStreamUtf8Parser :: Handle -> Handle -> IO ()
288_copyStreamUtf8Parser inh outh =
289 Stream.fold (Handle.write outh)
291 $ Stream.catRights $ Stream.parseMany
292 (Unicode.parseCharUtf8With Unicode.TransliterateCodingFailure)
293 $ Stream.unfold Handle.reader inh
295o_1_space_decode_encode_read :: BenchEnv -> [Benchmark]
296o_1_space_decode_encode_read env =
297 [ bgroup "decode-encode"
299 -- This needs an ascii file, as decode just errors out.
300 mkBench "encodeLatin1' . decodeLatin1" env $ \inh outh ->
301 copyStreamLatin1' inh outh
302 , mkBench "encodeLatin1 . decodeLatin1" env $ \inh outh ->
303 copyStreamLatin1 inh outh
304#ifdef INCLUDE_STRICT_UTF8
305 -- Requires valid unicode input
306 , mkBench "encodeUtf8' . decodeUtf8'" env $ \inh outh ->
307 _copyStreamUtf8' inh outh
308 , mkBench "encodeUtf8' . foldMany writeCharUtf8'" env $ \inh outh ->
309 _copyStreamUtf8'Fold inh outh
311 , mkBenchSmall "encodeUtf8 . parseMany parseCharUtf8" env
312 $ \inh outh -> _copyStreamUtf8Parser inh outh
313 , mkBenchSmall "encodeUtf8 . decodeUtf8" env $ \inh outh ->
314 copyStreamUtf8 inh outh
320 env <- mkHandleBenchEnv
321 defaultMain (allBenchmarks env)
326 [ bgroup (o_1_space_prefix moduleName) $ Prelude.concat
327 [ o_1_space_copy_read_group_ungroup env
328 , o_1_space_decode_encode_chunked env
329 , o_1_space_decode_encode_read env
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