@@ -54,6 +54,11 @@ module Streamly.Internal.Data.Array.Type
55 , pinnedClone
55 , pinnedClone
60+ , producer -- experimental
57 -- ** Elimination
62 -- ** Elimination
58 , unsafeIndexIO
63 , unsafeIndexIO
59 , getIndexUnsafe
64 , getIndexUnsafe
@@ -76,7 +81,7 @@ module Streamly.Internal.Data.Array.Type
76 , pinnedWriteN
81 , pinnedWriteN
77 , writeNUnsafe
82 , writeNUnsafe
78 , pinnedWriteNUnsafe
83 , pinnedWriteNUnsafe
79− , MA.ArrayUnsafe (..)
84+ -- , MA.ArrayUnsafe (..)
80 , pinnedWriteNAligned
85 , pinnedWriteNAligned
82 , pinnedWrite
87 , pinnedWrite
@@ -121,6 +126,7 @@ import GHC.Exts (IsList, IsString(..), Addr#)
122import GHC.IO (unsafePerformIO)
127import GHC.IO (unsafePerformIO)
123import GHC.Ptr (Ptr(..))
128import GHC.Ptr (Ptr(..))
129+import Streamly.Internal.Data.Producer.Type (Producer(..))
124import Streamly.Internal.Data.MutArray.Type (MutArray(..))
130import Streamly.Internal.Data.MutArray.Type (MutArray(..))
125import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
131import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
126import Streamly.Internal.Data.Fold.Type (Fold(..))
132import Streamly.Internal.Data.Fold.Type (Fold(..))
@@ -137,6 +143,7 @@ import qualified Streamly.Internal.Data.MutArray.Type as MA
137import qualified Streamly.Internal.Data.Stream.Type as D
143import qualified Streamly.Internal.Data.Stream.Type as D
138import qualified Streamly.Internal.Data.StreamK.Type as K
144import qualified Streamly.Internal.Data.StreamK.Type as K
139import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
145import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
146+import qualified Streamly.Internal.Data.Producer as Producer
140import qualified Streamly.Internal.Data.Unfold.Type as Unfold
147import qualified Streamly.Internal.Data.Unfold.Type as Unfold
141import qualified Text.ParserCombinators.ReadPrec as ReadPrec
148import qualified Text.ParserCombinators.ReadPrec as ReadPrec
@@ -414,16 +421,15 @@ pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
414 => Int -> D.Stream m a -> D.Stream m (Array a)
421 => Int -> D.Stream m a -> D.Stream m (Array a)
415pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
422pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
417−-- | Use the "reader" unfold instead.
424+-- | Convert a stream of arrays into a stream of their elements.
419−-- @concatChunks = unfoldMany reader@
421−-- We can try this if there are any fusion issues in the unfold.
426+-- >>> concatChunks = Stream.unfoldMany Array.reader
423{-# INLINE_NORMAL concatChunks #-}
428{-# INLINE_NORMAL concatChunks #-}
424−concatChunks :: forall m a. (MonadIO m, Unbox a)
429+concatChunks :: (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
425− => D.Stream m (Array a) -> D.Stream m a
430+-- XXX this requires MonadIO whereas the unfoldMany version does not
426concatChunks = MA.concatChunks . D.map unsafeThaw
431concatChunks = MA.concatChunks . D.map unsafeThaw
432+-- concatChunks = D.unfoldMany reader
428{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
434{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
429flattenArrays :: forall m a. (MonadIO m, Unbox a)
435flattenArrays :: forall m a. (MonadIO m, Unbox a)
@@ -488,6 +494,49 @@ byteLength = MA.byteLength . unsafeThaw
488length :: Unbox a => Array a -> Int
494length :: Unbox a => Array a -> Int
489length arr = MA.length (unsafeThaw arr)
495length arr = MA.length (unsafeThaw arr)
497+{-# INLINE_NORMAL producer #-}
498+producer :: forall m a. (Monad m, Unbox a) => Producer m (Array a) a
500+ Producer.translate unsafeThaw unsafeFreeze
501+ $ MA.producerWith (return . unsafeInlineIO)
503+-- | Unfold an array into a stream.
505+{-# INLINE_NORMAL reader #-}
506+reader :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
507+reader = Producer.simplify producer
509+-- | Unfold an array into a stream, does not check the end of the array, the
510+-- user is responsible for terminating the stream within the array bounds. For
511+-- high performance application where the end condition can be determined by
512+-- a terminating fold.
514+-- Written in the hope that it may be faster than "read", however, in the case
515+-- for which this was written, "read" proves to be faster even though the core
516+-- generated with unsafeRead looks simpler.
520+{-# INLINE_NORMAL readerUnsafe #-}
521+readerUnsafe :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
522+readerUnsafe = Unfold step inject
525+ inject (Array contents start end) =
526+ return (MA.ArrayUnsafe contents end start)
528+ {-# INLINE_LATE step #-}
529+ step (MA.ArrayUnsafe contents end p) = do
530+ -- unsafeInlineIO allows us to run this in Identity monad for pure
531+ -- toList/foldr case which makes them much faster due to not
532+ -- accumulating the list and fusing better with the pure consumers.
534+ -- This should be safe as the array contents are guaranteed to be
535+ -- evaluated/written to before we peek at them.
536+ let !x = unsafeInlineIO $ peekAt p contents
537+ let !p1 = INDEX_NEXT(p,a)
538+ return $ D.Yield x (MA.ArrayUnsafe contents end p1)
491-- | Unfold an array into a stream in reverse order.
540-- | Unfold an array into a stream in reverse order.
493{-# INLINE_NORMAL readerRev #-}
542{-# INLINE_NORMAL readerRev #-}