on master help sign in
Implement readRev to read an array in reverse order
705c2f2Harendra Kumar
src/Streamly/Internal/Data/Array/Foreign.hs+1
@@ -69,6 +69,7 @@ module Streamly.Internal.Data.Array.Foreign
69 , A.toStreamRev
69 , A.toStreamRev
70 , read
70 , read
71 , unsafeRead
71 , unsafeRead
72+ , A.readRev
72 -- , readChunksOf
73 -- , readChunksOf
73
74
74 -- * Random Access
75 -- * Random Access
src/Streamly/Internal/Data/Array/Foreign/Mut/Types.hs+39
@@ -77,6 +77,7 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Types
77 -- * Unfolds
77 -- * Unfolds
78 , ReadUState
78 , ReadUState
79 , read
79 , read
80+ , readRev
80 , flattenArrays
81 , flattenArrays
81 , flattenArraysRev
82 , flattenArraysRev
82
83
@@ -523,6 +524,33 @@ read = Unfold step inject
523 return $ D.Yield x
524 return $ D.Yield x
524 (ReadUState fp (p `plusPtr` sizeOf (undefined :: a)))
525 (ReadUState fp (p `plusPtr` sizeOf (undefined :: a)))
525
526
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+
526data FlattenState s a =
554data FlattenState s a =
527 OuterLoop s
555 OuterLoop s
528 | InnerLoop s !(ForeignPtr a) !(Ptr a) !(Ptr a)
556 | InnerLoop s !(ForeignPtr a) !(Ptr a) !(Ptr a)
@@ -561,6 +589,12 @@ flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
561 return $ D.Yield x (InnerLoop st startf
589 return $ D.Yield x (InnerLoop st startf
562 (p `plusPtr` sizeOf (undefined :: a)) end)
590 (p `plusPtr` sizeOf (undefined :: a)) end)
563
591
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+--
564{-# INLINE_NORMAL flattenArraysRev #-}
598{-# INLINE_NORMAL flattenArraysRev #-}
565flattenArraysRev :: forall m a. (MonadIO m, Storable a)
599flattenArraysRev :: forall m a. (MonadIO m, Storable a)
566 => D.Stream m (Array a) -> D.Stream m a
600 => D.Stream m (Array a) -> D.Stream m a
@@ -667,6 +701,11 @@ toStreamK Array{..} =
667 return r
701 return r
668 in x `K.cons` go (p `plusPtr` sizeOf (undefined :: a))
702 in x `K.cons` go (p `plusPtr` sizeOf (undefined :: a))
669
703
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.
670{-# INLINE_NORMAL toStreamDRev #-}
709{-# INLINE_NORMAL toStreamDRev #-}
671toStreamDRev :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
710toStreamDRev :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
672toStreamDRev Array{..} =
711toStreamDRev Array{..} =
src/Streamly/Internal/Data/Array/Foreign/Types.hs+16
@@ -45,6 +45,7 @@ module Streamly.Internal.Data.Array.Foreign.Types
45 , foldr
45 , foldr
46 , splitAt
46 , splitAt
47
47
48+ , readRev
48 , toStreamD
49 , toStreamD
49 , toStreamDRev
50 , toStreamDRev
50 , toStreamK
51 , toStreamK
@@ -97,6 +98,7 @@ import GHC.ForeignPtr (touchForeignPtr, unsafeForeignPtrToPtr)
97import GHC.IO (unsafePerformIO)
98import GHC.IO (unsafePerformIO)
98import GHC.Ptr (Ptr(..))
99import GHC.Ptr (Ptr(..))
99import Streamly.Internal.Data.Fold.Types (Fold(..))
100import Streamly.Internal.Data.Fold.Types (Fold(..))
101+import Streamly.Internal.Data.Unfold.Types (Unfold(..))
100import Text.Read (readPrec, readListPrec, readListPrecDefault)
102import Text.Read (readPrec, readListPrec, readListPrecDefault)
101
103
102import Prelude hiding (length, foldr, read, unlines, splitAt)
104import Prelude hiding (length, foldr, read, unlines, splitAt)
@@ -104,6 +106,7 @@ import Prelude hiding (length, foldr, read, unlines, splitAt)
104import qualified Streamly.Internal.Data.Array.Foreign.Mut.Types as MA
106import qualified Streamly.Internal.Data.Array.Foreign.Mut.Types as MA
105import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
107import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
106import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
108import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
109+import qualified Streamly.Internal.Data.Unfold.Types as Unfold
107import qualified GHC.Exts as Exts
110import qualified GHC.Exts as Exts
108
111
109#if __GLASGOW_HASKELL__ < 808
112#if __GLASGOW_HASKELL__ < 808
@@ -333,6 +336,12 @@ flattenArrays :: forall m a. (MonadIO m, Storable a)
333 => D.Stream m (Array a) -> D.Stream m a
336 => D.Stream m (Array a) -> D.Stream m a
334flattenArrays = MA.flattenArrays . D.map unsafeThaw
337flattenArrays = MA.flattenArrays . D.map unsafeThaw
335
338
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+--
336{-# INLINE_NORMAL flattenArraysRev #-}
345{-# INLINE_NORMAL flattenArraysRev #-}
337flattenArraysRev :: forall m a. (MonadIO m, Storable a)
346flattenArraysRev :: forall m a. (MonadIO m, Storable a)
338 => D.Stream m (Array a) -> D.Stream m a
347 => D.Stream m (Array a) -> D.Stream m a
@@ -377,6 +386,13 @@ byteLength = MA.byteLength . unsafeThaw
377length :: forall a. Storable a => Array a -> Int
386length :: forall a. Storable a => Array a -> Int
378length arr = MA.length (unsafeThaw arr)
387length arr = MA.length (unsafeThaw arr)
379
388
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+
380{-# INLINE_NORMAL toStreamD #-}
396{-# INLINE_NORMAL toStreamD #-}
381toStreamD :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
397toStreamD :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
382toStreamD arr = MA.toStreamD (unsafeThaw arr)
398toStreamD 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)
93--
93--
94-- Same as the following but more efficient:
94-- Same as the following but more efficient:
95--
95--
96−-- > concat = S.concatMap A.read
96+-- > concat = Stream.concatUnfold Array.read
97--
97--
98-- @since 0.7.0
98-- @since 0.7.0
99{-# INLINE concat #-}
99{-# INLINE concat #-}
@@ -102,12 +102,11 @@ concat :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
102-- concat m = D.fromStreamD $ D.concatMap A.toStreamD (D.toStreamD m)
102-- concat m = D.fromStreamD $ D.concatMap A.toStreamD (D.toStreamD m)
103concat m = D.fromStreamD $ D.concatUnfold A.read (D.toStreamD m)
103concat m = D.fromStreamD $ D.concatUnfold A.read (D.toStreamD m)
104
104
105−-- XXX should we have a reverseArrays API to reverse the stream of arrays
106−-- instead?
107−--
108-- | Convert a stream of arrays into a stream of their elements reversing the
105-- | Convert a stream of arrays into a stream of their elements reversing the
109-- contents of each array before flattening.
106-- contents of each array before flattening.
110--
107--
108+-- > concatRev = Stream.concatUnfold Array.readRev
109+--
111-- @since 0.7.0
110-- @since 0.7.0
112{-# INLINE concatRev #-}
111{-# INLINE concatRev #-}
113concatRev :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
112concatRev :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a