on master help sign in
Implement readRev to read an array in reverse order
commit705c2f2418774ece036891ba34c31089b4b3abc1 authorHarendra Kumar <harendra@composewell.com> dateWed 27 Jan 2021, 18:36 (6 years ago) parentbffdd45
4 files changed+59−4
src/Streamly/Internal/Data/Array/Foreign.hs+1 src/Streamly/Internal/Data/Array/Foreign/Mut/Types.hs+39 src/Streamly/Internal/Data/Array/Foreign/Types.hs+16 src/Streamly/Internal/Data/Array/Stream/Foreign.hs+3−4
src/Streamly/Internal/Data/Array/Foreign.hs+1
@@ -69,6 +69,7 @@ module Streamly.Internal.Data.Array.Foreign
6969 , A.toStreamRev
7070 , read
7171 , unsafeRead
72+ , A.readRev
7273 -- , readChunksOf
7374
7475 -- * Random Access
src/Streamly/Internal/Data/Array/Foreign/Mut/Types.hs+39
@@ -77,6 +77,7 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Types
7777 -- * Unfolds
7878 , ReadUState
7979 , read
80+ , readRev
8081 , flattenArrays
8182 , flattenArraysRev
8283
@@ -523,6 +524,33 @@ read = Unfold step inject
523524 return $ D.Yield x
524525 (ReadUState fp (p `plusPtr` sizeOf (undefined :: a)))
525526
527+-- | Unfold an array into a stream in reverse order.
528+--
529+-- /Internal/
530+{-# INLINE_NORMAL readRev #-}
531+readRev :: forall m a. (Monad m, Storable a) => Unfold m (Array a) a
532+readRev = Unfold step inject
533+ where
534+
535+ inject (Array fp end _) =
536+ let p = end `plusPtr` negate (sizeOf (undefined :: a))
537+ in return $ ReadUState fp p
538+
539+ {-# INLINE_LATE step #-}
540+ step (ReadUState fp@(ForeignPtr start _) p) | p < Ptr start =
541+ let x = unsafeInlineIO $ touchForeignPtr fp
542+ in x `seq` return D.Stop
543+ step (ReadUState fp p) = do
544+ -- unsafeInlineIO allows us to run this in Identity monad for pure
545+ -- toList/foldr case which makes them much faster due to not
546+ -- accumulating the list and fusing better with the pure consumers.
547+ --
548+ -- This should be safe as the array contents are guaranteed to be
549+ -- evaluated/written to before we peek at them.
550+ let !x = unsafeInlineIO $ peek p
551+ return $ D.Yield x
552+ (ReadUState fp (p `plusPtr` negate (sizeOf (undefined :: a))))
553+
526554data FlattenState s a =
527555 OuterLoop s
528556 | InnerLoop s !(ForeignPtr a) !(Ptr a) !(Ptr a)
@@ -561,6 +589,12 @@ flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
561589 return $ D.Yield x (InnerLoop st startf
562590 (p `plusPtr` sizeOf (undefined :: a)) end)
563591
592+-- | Use the "readRev" unfold instead.
593+--
594+-- @flattenArrays = concatUnfold readRev@
595+--
596+-- We can try this if there are any fusion issues in the unfold.
597+--
564598{-# INLINE_NORMAL flattenArraysRev #-}
565599flattenArraysRev :: forall m a. (MonadIO m, Storable a)
566600 => D.Stream m (Array a) -> D.Stream m a
@@ -667,6 +701,11 @@ toStreamK Array{..} =
667701 return r
668702 in x `K.cons` go (p `plusPtr` sizeOf (undefined :: a))
669703
704+-- | Use the 'readRev' unfold instead.
705+--
706+-- @toStreamDRev = D.unfold readRev@
707+--
708+-- We can try this if the unfold has any perf issues.
670709{-# INLINE_NORMAL toStreamDRev #-}
671710toStreamDRev :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
672711toStreamDRev Array{..} =
src/Streamly/Internal/Data/Array/Foreign/Types.hs+16
@@ -45,6 +45,7 @@ module Streamly.Internal.Data.Array.Foreign.Types
4545 , foldr
4646 , splitAt
4747
48+ , readRev
4849 , toStreamD
4950 , toStreamDRev
5051 , toStreamK
@@ -97,6 +98,7 @@ import GHC.ForeignPtr (touchForeignPtr, unsafeForeignPtrToPtr)
9798import GHC.IO (unsafePerformIO)
9899import GHC.Ptr (Ptr(..))
99100import Streamly.Internal.Data.Fold.Types (Fold(..))
101+import Streamly.Internal.Data.Unfold.Types (Unfold(..))
100102import Text.Read (readPrec, readListPrec, readListPrecDefault)
101103
102104import Prelude hiding (length, foldr, read, unlines, splitAt)
@@ -104,6 +106,7 @@ import Prelude hiding (length, foldr, read, unlines, splitAt)
104106import qualified Streamly.Internal.Data.Array.Foreign.Mut.Types as MA
105107import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
106108import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
109+import qualified Streamly.Internal.Data.Unfold.Types as Unfold
107110import qualified GHC.Exts as Exts
108111
109112#if __GLASGOW_HASKELL__ < 808
@@ -333,6 +336,12 @@ flattenArrays :: forall m a. (MonadIO m, Storable a)
333336 => D.Stream m (Array a) -> D.Stream m a
334337flattenArrays = MA.flattenArrays . D.map unsafeThaw
335338
339+-- | Use the "readRev" unfold instead.
340+--
341+-- @flattenArrays = concatUnfold readRev@
342+--
343+-- We can try this if there are any fusion issues in the unfold.
344+--
336345{-# INLINE_NORMAL flattenArraysRev #-}
337346flattenArraysRev :: forall m a. (MonadIO m, Storable a)
338347 => D.Stream m (Array a) -> D.Stream m a
@@ -377,6 +386,13 @@ byteLength = MA.byteLength . unsafeThaw
377386length :: forall a. Storable a => Array a -> Int
378387length arr = MA.length (unsafeThaw arr)
379388
389+-- | Unfold an array into a stream in reverse order.
390+--
391+-- /Internal/
392+{-# INLINE_NORMAL readRev #-}
393+readRev :: forall m a. (Monad m, Storable a) => Unfold m (Array a) a
394+readRev = Unfold.lmap unsafeThaw MA.readRev
395+
380396{-# INLINE_NORMAL toStreamD #-}
381397toStreamD :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
382398toStreamD arr = MA.toStreamD (unsafeThaw arr)
src/Streamly/Internal/Data/Array/Stream/Foreign.hs+3−4
@@ -93,7 +93,7 @@ arraysOf n str = D.fromStreamD $ A.arraysOf n (D.toStreamD str)
9393--
9494-- Same as the following but more efficient:
9595--
96−-- > concat = S.concatMap A.read
96+-- > concat = Stream.concatUnfold Array.read
9797--
9898-- @since 0.7.0
9999{-# INLINE concat #-}
@@ -102,12 +102,11 @@ concat :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
102102-- concat m = D.fromStreamD $ D.concatMap A.toStreamD (D.toStreamD m)
103103concat m = D.fromStreamD $ D.concatUnfold A.read (D.toStreamD m)
104104
105−-- XXX should we have a reverseArrays API to reverse the stream of arrays
106−-- instead?
107−--
108105-- | Convert a stream of arrays into a stream of their elements reversing the
109106-- contents of each array before flattening.
110107--
108+-- > concatRev = Stream.concatUnfold Array.readRev
109+--
111110-- @since 0.7.0
112111{-# INLINE concatRev #-}
113112concatRev :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a