@@ -1,3 +1,4 @@
1+{-# LANGUAGE FlexibleContexts #-}
12-- |
23-- Module : Streamly.String
34-- Copyright : (c) 2018 Composewell Technologies
@@ -52,23 +53,25 @@ module Streamly.String
5253 , foldLines
5354 , foldWords
5455 , lines
55− , words{-
56+ , words
5657 , unlines
57− , unwords-}
58+ , unwords
5859 )
5960where
6061
6162import Control.Monad.IO.Class (MonadIO)
62−import Data.Char (isSpace, ord)
63+import Data.Char (ord)
6364import Data.Word (Word8)
6465import GHC.Base (unsafeChr)
65−import Streamly (IsStream)
66+import Streamly (IsStream, MonadAsync)
6667import Prelude hiding (String, lines, words, unlines, unwords)
6768import Streamly.Fold (Fold)
6869import Streamly.Mem.Array (Array, toArray)
6970
7071import qualified Streamly.Prelude as S
7172import qualified Streamly.Fold as FL
73+import qualified Streamly.Mem.Array.Types as A (unlines)
74+import qualified Streamly.Mem.Array as A
7275import qualified Streamly.Streams.StreamD as D
7376
7477-- type String = List Char
@@ -112,12 +115,13 @@ encodeChar8Unchecked :: (IsStream t, Monad m) => t m Char -> t m Word8
112115encodeChar8Unchecked = S.map (fromIntegral . ord)
113116
114117-- | Decode a UTF-8 encoded bytestream to a stream of Unicode characters.
118+-- The incoming stream is truncated if an invalid codepoint is encountered.
115119{-# INLINE decodeUtf8 #-}
116120decodeUtf8 :: (Monad m, IsStream t) => t m Word8 -> t m Char
117121decodeUtf8 = D.fromStreamD . D.decodeUtf8 . D.toStreamD
118122
119−{-# INLINE encodeUtf8 #-}
120123-- | Encode a stream of Unicode characters to a UTF-8 encoded bytestream.
124+{-# INLINE encodeUtf8 #-}
121125encodeUtf8 :: (Monad m, IsStream t) => t m Char -> t m Word8
122126encodeUtf8 = D.fromStreamD . D.encodeUtf8 . D.toStreamD
123127
@@ -161,6 +165,18 @@ foldLines = flip (FL.splitSuffixBy (== '\n'))
161165foldWords :: (Monad m, IsStream t) => t m Char -> Fold m Char b -> t m b
162166foldWords = flip (FL.wordsBy isSpace)
163167
168+foreign import ccall unsafe "u_iswspace"
169+ iswspace :: Int -> Int
170+
171+-- Code copied from base/Data.Char to INLINE it
172+{-# INLINE isSpace #-}
173+isSpace :: Char -> Bool
174+isSpace c
175+ | uc <= 0x377 = uc == 32 || uc - 0x9 <= 4 || uc == 0xa0
176+ | otherwise = iswspace (ord c) /= 0
177+ where
178+ uc = fromIntegral (ord c) :: Word
179+
164180{-# INLINE lines #-}
165181lines :: (MonadIO m, IsStream t) => t m Char -> t m (Array Char)
166182lines = FL.splitSuffixBy (== '\n') toArray
@@ -169,10 +185,10 @@ lines = FL.splitSuffixBy (== '\n') toArray
169185words :: (MonadIO m, IsStream t) => t m Char -> t m (Array Char)
170186words = FL.wordsBy isSpace toArray
171187
172−{-
173−unlines :: IsStream t => t m (Array Char) -> t m Char
174−unlines = undefined
188+{-# INLINE unlines #-}
189+unlines :: (MonadIO m, IsStream t) => t m (Array Char) -> t m Char
190+unlines = D.fromStreamD . A.unlines . D.toStreamD
175191
176−unwords :: IsStream t => t m (Array Char) -> t m Char
177−unwords = undefined
178−-}
192+{-# INLINE unwords #-}
193+unwords :: (MonadAsync m, IsStream t) => t m (Array Char) -> t m Char
194+unwords = A.flattenArrays . (S.intersperseM (return $ A.fromList " "))