2-- Module : Streamly.String
3-- Copyright : (c) 2018 Composewell Technologies
6-- Maintainer : harendra.kumar@gmail.com
7-- Stability : experimental
10-- Stream of 'Char' are the equivalent of Haskell Strings but without any
11-- performance issues that are usually associated with the 'String' type.
12-- Haskell lists are not suitable for storage in GC memory. We use streams for
13-- processing and arrays for storing. We can use the usual stream processing
14-- routines on these 'Char' streams. Stream processing is very efficient due to
15-- stream fusion. If strings are to be stored or buffered in memory, they can
16-- be encoded to 'Word8' arrays using the encoding routines provided in the
17-- module. Therefore, a separate type for text representation is not required.
19-- The 'String' type in this module is just a synonym for the type @List Char@.
20-- It provides better performance compared to the standard Haskell @String@
21-- type and can be used almost as a drop-in replacement, especially when used
22-- with @OverloadedStrings@ extension, with little differences.
24-- See "Streamly.List", <src/docs/streamly-vs-lists.md> for more details and
25-- <src/test/PureStreams.hs> for comprehensive usage examples.
27-- TBD write a note on performance comparison with text, bytestrings, lists and
34 -- * Encoding and Decoding
36 , encodeChar8Unchecked
42 -- * Unicode aware operations
48 -- * Operations on character strings
49 , strip -- (dropAround isSpace)
61import Control.Monad.IO.Class (MonadIO)
62import Data.Char (isSpace, ord)
63import Data.Word (Word8)
64import GHC.Base (unsafeChr)
65import Streamly (IsStream)
66import Prelude hiding (String, lines, words, unlines, unwords)
67import Streamly.Fold (Fold)
68import Streamly.Mem.Array (Array, toArray)
70import qualified Streamly.Prelude as S
71import qualified Streamly.Fold as FL
72import qualified Streamly.Streams.StreamD as D
74-- type String = List Char
76-------------------------------------------------------------------------------
77-- Encoding/Decoding Characters
78-------------------------------------------------------------------------------
80-- decodeWith :: TextEncoding -> t m Word8 -> t m Char
81-- decodeWith = undefined
83-------------------------------------------------------------------------------
84-- Encoding/Decoding Unicode Characters
85-------------------------------------------------------------------------------
87-- | Decode a stream of bytes to Unicode characters by mapping each byte to a
88-- corresponding Unicode 'Char' in 0-255 range.
89{-# INLINE decodeChar8 #-}
90decodeChar8 :: (IsStream t, Monad m) => t m Word8 -> t m Char
91decodeChar8 = S.map (unsafeChr . fromIntegral)
93-- | Encode a stream of Unicode characters to bytes by mapping each character
94-- to a byte in 0-255 range. Throws an error if the input stream contains
95-- characters beyond 255.
96{-# INLINE encodeChar8 #-}
97encodeChar8 :: (IsStream t, Monad m) => t m Char -> t m Word8
98encodeChar8 = S.map convert
101 let codepoint = ord c
102 in if codepoint > 255
103 then error $ "Streamly.String.encodeChar8 invalid \
104 \input char codepoint " ++ show codepoint
105 else fromIntegral codepoint
107-- | Like 'encodeChar8' but silently truncates and maps input characters beyond
108-- 255 to (incorrect) chars in 0-255 range. No error or exception is thrown
109-- when such truncation occurs.
110{-# INLINE encodeChar8Unchecked #-}
111encodeChar8Unchecked :: (IsStream t, Monad m) => t m Char -> t m Word8
112encodeChar8Unchecked = S.map (fromIntegral . ord)
114-- | Decode a UTF-8 encoded bytestream to a stream of Unicode characters.
115{-# INLINE decodeUtf8 #-}
116decodeUtf8 :: (Monad m, IsStream t) => t m Word8 -> t m Char
117decodeUtf8 = D.fromStreamD . D.decodeUtf8 . D.toStreamD
119{-# INLINE encodeUtf8 #-}
120-- | Encode a stream of Unicode characters to a UTF-8 encoded bytestream.
121encodeUtf8 :: (Monad m, IsStream t) => t m Char -> t m Word8
122encodeUtf8 = D.fromStreamD . D.encodeUtf8 . D.toStreamD
125-------------------------------------------------------------------------------
126-- Unicode aware operations on strings
127-------------------------------------------------------------------------------
129toCaseFold :: IsStream t => t m Char -> t m Char
130toCaseFold = undefined
132toLower :: IsStream t => t m Char -> t m Char
135toUpper :: IsStream t => t m Char -> t m Char
138toTitle :: IsStream t => t m Char -> t m Char
141-------------------------------------------------------------------------------
142-- Utility operations on strings
143-------------------------------------------------------------------------------
145strip :: IsStream t => t m Char -> t m Char
148stripEnd :: IsStream t => t m Char -> t m Char
152{-# INLINE stripStart #-}
153stripStart :: (Monad m, IsStream t) => t m Char -> t m Char
154stripStart = S.dropWhile isSpace
156{-# INLINE foldLines #-}
157foldLines :: (Monad m, IsStream t) => t m Char -> Fold m Char b -> t m b
158foldLines = flip (FL.splitSuffixBy (== '\n'))
160{-# INLINE foldWords #-}
161foldWords :: (Monad m, IsStream t) => t m Char -> Fold m Char b -> t m b
162foldWords = flip (FL.wordsBy isSpace)
165lines :: (MonadIO m, IsStream t) => t m Char -> t m (Array Char)
166lines = FL.splitSuffixBy (== '\n') toArray
169words :: (MonadIO m, IsStream t) => t m Char -> t m (Array Char)
170words = FL.wordsBy isSpace toArray
173unlines :: IsStream t => t m (Array Char) -> t m Char
176unwords :: IsStream t => t m (Array Char) -> t m Char
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