on master help sign in
Add fromByteStr# and fromStr#

Routines to generate byte/char streams from Haskell string literals.

commit4bb8b7c950ffeee9d5c9c3ca23c65be93ca34f0b authorHarendra Kumar <harendra@composewell.com> dateSun 7 Aug 2022, 03:39 (4 years ago) parent64512ce
4 files changed+80−14
core/src/Streamly/Internal/Data/Stream/Generate.hs+44−4 core/src/Streamly/Internal/Data/Stream/StreamD/Generate.hs+6−5 core/src/Streamly/Internal/Data/Unfold.hs+4−5 src/Streamly/Internal/Unicode/Stream.hs+26
core/src/Streamly/Internal/Data/Stream/Generate.hs+44−4
@@ -30,16 +30,20 @@ module Streamly.Internal.Data.Stream.Generate
3030
3131 -- * From memory
3232 , fromPtr
33+ , fromPtrN
34+ , fromByteStr#
35+ -- , fromByteArray#
3336 )
3437where
3538
3639import Control.Monad.IO.Class (MonadIO)
40+import Data.Word (Word8)
3741import Foreign.Storable (Storable)
38−import Foreign.Ptr (Ptr)
42+import GHC.Exts (Addr#, Ptr (Ptr))
3943import Streamly.Internal.Data.Stream.Type (Stream, fromStreamK, toStreamK)
4044import Streamly.Internal.Data.Unfold.Type (Unfold)
4145
42−import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
46+import qualified Streamly.Internal.Data.Stream.StreamD as D
4347import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
4448import qualified Streamly.Internal.Data.Stream.Type as Stream
4549
@@ -48,6 +52,7 @@ import qualified Streamly.Internal.Data.Stream.Type as Stream
4852-- >>> import qualified Streamly.Data.Fold as Fold
4953-- >>> import qualified Streamly.Data.Unfold as Unfold
5054-- >>> import qualified Streamly.Internal.Data.Stream as Stream
55+-- >>> import GHC.Exts (Ptr (Ptr))
5156
5257
5358------------------------------------------------------------------------------
@@ -151,6 +156,41 @@ fromFoldableM = Prelude.foldr Stream.consM Stream.nil
151156-- From pointers
152157------------------------------------------------------------------------------
153158
159+-- | Keep reading 'Storable' elements from 'Ptr' onwards.
160+--
161+-- /Unsafe:/ The caller is responsible for safe addressing.
162+--
163+-- /Pre-release/
154164{-# INLINE fromPtr #-}
155−fromPtr :: (MonadIO m, Storable a) => Int -> Ptr a -> Stream m a
156−fromPtr n = Stream.fromStreamD . D.fromPtr n
165+fromPtr :: (MonadIO m, Storable a) => Ptr a -> Stream m a
166+fromPtr = Stream.fromStreamD . D.fromPtr
167+
168+-- | Take @n@ 'Storable' elements starting from 'Ptr' onwards.
169+--
170+-- >>> fromPtrN n = Stream.take n . Stream.fromPtr
171+--
172+-- /Unsafe:/ The caller is responsible for safe addressing.
173+--
174+-- /Pre-release/
175+{-# INLINE fromPtrN #-}
176+fromPtrN :: (MonadIO m, Storable a) => Int -> Ptr a -> Stream m a
177+fromPtrN n = Stream.fromStreamD . D.take n . D.fromPtr
178+
179+-- | Read bytes from an 'Addr#' until a 0 byte is encountered, the 0 byte is
180+-- not included in the stream.
181+--
182+-- >>> fromByteStr# addr = Stream.takeWhile (/= 0) $ Stream.fromPtr $ Ptr addr
183+--
184+-- /Unsafe:/ The caller is responsible for safe addressing.
185+--
186+-- Note that this is completely safe when reading from Haskell string
187+-- literals because they are guaranteed to be NULL terminated:
188+--
189+-- >>> Stream.fold Fold.toList $ Stream.fromByteStr# "\1\2\3\0"#
190+-- [1,2,3]
191+--
192+{-# INLINE fromByteStr# #-}
193+fromByteStr# :: MonadIO m => Addr# -> Stream m Word8
194+fromByteStr# addr =
195+ Stream.fromStreamD $ D.takeWhile (/= 0) $ D.fromPtr $ Ptr addr
196+
core/src/Streamly/Internal/Data/Stream/StreamD/Generate.hs+6−5
@@ -470,14 +470,15 @@ fromListM = Stream step
470470-- From pointers
471471-------------------------------------------------------------------------------
472472
473+-- | Read an infinite stream from a pointer, advancing the pointer as needed.
474+-- The caller is responsible to end the stream safely.
473475{-# INLINE fromPtr #-}
474−fromPtr :: forall m a. (MonadIO m, Storable a) => Int -> Ptr a -> Stream m a
475−fromPtr count ptr = Stream step (count, ptr)
476+fromPtr :: forall m a. (MonadIO m, Storable a) => Ptr a -> Stream m a
477+fromPtr = Stream step
476478
477479 where
478480
479481 {-# INLINE_LATE step #-}
480− step _ (0, _) = return Stop
481− step _ (n, p) = do
482+ step _ p = do
482483 x <- liftIO $ peek p
483− return $ Yield x (n - 1, PTR_NEXT(p, a))
484+ return $ Yield x (PTR_NEXT(p, a))
core/src/Streamly/Internal/Data/Unfold.hs+4−5
@@ -177,7 +177,7 @@ module Streamly.Internal.Data.Unfold
177177 , fromList
178178 , fromListM
179179
180− -- ** From Pointer
180+ -- ** From Memory
181181 , fromPtr
182182
183183 , fromStreamK
@@ -636,16 +636,15 @@ fromListM = Unfold step pure
636636 step [] = pure Stop
637637
638638{-# INLINE fromPtr #-}
639−fromPtr :: forall m a. (MonadIO m, Storable a) => Unfold m (Int, Ptr a) a
639+fromPtr :: forall m a. (MonadIO m, Storable a) => Unfold m (Ptr a) a
640640fromPtr = Unfold step return
641641
642642 where
643643
644644 {-# INLINE_LATE step #-}
645− step (0, _) = return Stop
646− step (n, p) = do
645+ step p = do
647646 x <- liftIO $ peek p
648− return $ Yield x (n - 1, PTR_NEXT(p, a))
647+ return $ Yield x (PTR_NEXT(p, a))
649648
650649------------------------------------------------------------------------------
651650-- Specialized Generation
src/Streamly/Internal/Unicode/Stream.hs+26
@@ -72,6 +72,9 @@ module Streamly.Internal.Unicode.Stream
7272 , decodeUtf8ArraysD'
7373 , decodeUtf8ArraysD_
7474
75+ -- * Decoding String Literals
76+ , fromStr#
77+
7578 -- * Deprecations
7679 , decodeUtf8Lax
7780 , encodeLatin1Lax
@@ -94,6 +97,7 @@ import Foreign.Marshal.Alloc (mallocBytes)
9497import Foreign.Storable (Storable(..))
9598import Fusion.Plugin.Types (Fuse(..))
9699import GHC.Base (assert, unsafeChr)
100+import GHC.Exts (Addr#)
97101import GHC.IO.Encoding.Failure (isSurrogate)
98102import GHC.Ptr (Ptr (..), plusPtr)
99103import System.IO.Unsafe (unsafePerformIO)
@@ -114,6 +118,7 @@ import qualified Streamly.Internal.Data.Fold as Fold
114118import qualified Streamly.Internal.Data.Unfold as Unfold
115119import qualified Streamly.Internal.Data.Parser as Parser
116120import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
121+import qualified Streamly.Internal.Data.Stream as Stream
117122import qualified Streamly.Internal.Data.Stream.Serial as Serial
118123import qualified Streamly.Internal.Data.Array.Unboxed as Array
119124import qualified Streamly.Internal.Data.Array.Unboxed.Type as A
@@ -124,9 +129,11 @@ import Prelude hiding (lines, words, unlines, unwords)
124129
125130-- $setup
126131-- >>> :m
132+-- >>> :set -XMagicHash
127133-- >>> import Prelude hiding (lines, words, unlines, unwords)
128134-- >>> import qualified Streamly.Prelude as Stream
129135-- >>> import qualified Streamly.Data.Fold as Fold
136+-- >>> import qualified Streamly.Internal.Unicode.Stream as Unicode
130137-- >>> import Streamly.Internal.Unicode.Stream
131138
132139-------------------------------------------------------------------------------
@@ -980,6 +987,25 @@ encodeUtf8_ = fromStreamD . encodeUtf8D_ . toStreamD
980987encodeUtf8Lax :: (IsStream t, Monad m) => t m Char -> t m Word8
981988encodeUtf8Lax = encodeUtf8
982989
990+-------------------------------------------------------------------------------
991+-- Decoding string literals
992+-------------------------------------------------------------------------------
993+
994+-- | Read UTF-8 encoded bytes as chars from an 'Addr#' until a 0 byte is
995+-- encountered, the 0 byte is not included in the stream.
996+--
997+-- /Unsafe:/ The caller is responsible for safe addressing.
998+--
999+-- Note that this is completely safe when reading from Haskell string
1000+-- literals because they are guaranteed to be NULL terminated:
1001+--
1002+-- >>> Stream.fold Fold.toList (Unicode.fromStr# "Haskell"#)
1003+-- "Haskell"
1004+--
1005+{-# INLINE fromStr# #-}
1006+fromStr# :: MonadIO m => Addr# -> SerialT m Char
1007+fromStr# addr = decodeUtf8 $ Stream.fromByteStr# addr
1008+
9831009-------------------------------------------------------------------------------
9841010-- Encode streams of containers
9851011-------------------------------------------------------------------------------