1{-# LANGUAGE BangPatterns #-}
3{-# LANGUAGE MagicHash #-}
4{-# LANGUAGE RecordWildCards #-}
5{-# LANGUAGE UnboxedTuples #-}
6{-# LANGUAGE ScopedTypeVariables #-}
11-- Module : Streamly.Mem.Array.Stream
12-- Copyright : (c) 2019 Composewell Technologies
15-- Maintainer : harendra.kumar@gmail.com
16-- Stability : experimental
19-- Combinators to efficiently manipulate streams of arrays.
21module Streamly.Mem.Array.Stream
26 -- * Flattening to elements
28 -- , _flattenArraysRev
40import Control.Monad.IO.Class (MonadIO(..))
41-- import Data.Functor.Identity (Identity)
42import Data.Word (Word8)
43import Foreign.ForeignPtr (withForeignPtr)
44import Foreign.Ptr (minusPtr, plusPtr, castPtr)
45import Foreign.Storable (Storable(..))
46import Prelude hiding (length, null, last, map, (!!), read)
48import Streamly.Mem.Array.Types (Array(..), length)
49import Streamly.Streams.Serial (SerialT)
50import Streamly.Streams.StreamK.Type (IsStream)
52import qualified Streamly.Mem.Array.Types as A
53import qualified Streamly.Prelude as S
54import qualified Streamly.Streams.StreamD as D
55import qualified Streamly.Streams.Prelude as P
57-- | Convert a stream of arrays into a stream of their elements.
59-- Same as the following but more efficient:
61-- > flatten = S.concatMap A.read
65flatten :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
66flatten m = D.fromStreamD $ A.flattenArrays (D.toStreamD m)
68-- XXX should we have a reverseArrays API to reverse the stream of arrays
71-- | Convert a stream of arrays into a stream of their elements reversing the
72-- contents of each array before flattening.
75{-# INLINE _flattenArraysRev #-}
76_flattenArraysRev :: (IsStream t, MonadIO m, Storable a) => t m (Array a) -> t m a
77_flattenArraysRev m = D.fromStreamD $ A.flattenArraysRev (D.toStreamD m)
79-- XXX use an Array instead as separator? Or use a separate unlinesArraysBySeq
82-- | Flatten a stream of arrays appending the given element after each
86{-# INLINE unlinesBy #-}
87unlinesBy :: (MonadIO m, IsStream t, Storable a)
88 => a -> t m (Array a) -> t m a
89unlinesBy x = D.fromStreamD . A.unlines x . D.toStreamD
91-- | Split a stream of arrays on a given separator byte, dropping the separator
92-- and coalescing all the arrays between two separators into a single array.
97 :: (IsStream t, MonadIO m)
101splitOn byte s = D.fromStreamD $ A.splitOn byte $ D.toStreamD s
103-- | Coalesce adajcent arrays in incoming stream to form bigger arrays of a
104-- maximum specified size.
107{-# INLINE compact #-}
108compact :: (MonadIO m, Storable a)
109 => Int -> SerialT m (Array a) -> SerialT m (Array a)
111 D.fromStreamD $ A.packArraysChunksOf n (D.toStreamD xs)
113-- | Groups the elements in an input stream into arrays of given size.
115-- Same as the following but more efficient:
117-- > arraysOf n = FL.groupsOf n (FL.toArrayN n)
120{-# INLINE arraysOf #-}
121arraysOf :: (IsStream t, MonadIO m, Storable a)
122 => Int -> t m a -> t m (Array a)
124 D.fromStreamD $ A.fromStreamDArraysOf n (D.toStreamD str)
126-- XXX Both of these implementations of splicing seem to perform equally well.
127-- We need to perform benchmarks over a range of sizes though.
129-- CAUTION! length must more than equal to lengths of all the arrays in the
131{-# INLINE spliceArraysLenUnsafe #-}
132spliceArraysLenUnsafe :: (MonadIO m, Storable a)
133 => Int -> SerialT m (Array a) -> m (Array a)
134spliceArraysLenUnsafe len buffered = do
135 arr <- liftIO $ A.newArray len
136 end <- S.foldlM' writeArr (aEnd arr) buffered
137 return $ arr {aEnd = end}
141 writeArr dst Array{..} =
142 liftIO $ withForeignPtr aStart $ \src -> do
143 let count = aEnd `minusPtr` src
144 A.memcpy (castPtr dst) (castPtr src) count
145 return $ dst `plusPtr` count
147{-# INLINE _spliceArraysBuffered #-}
148_spliceArraysBuffered :: (MonadIO m, Storable a)
149 => SerialT m (Array a) -> m (Array a)
150_spliceArraysBuffered s = do
151 buffered <- P.foldr S.cons S.nil s
152 len <- S.sum (S.map length buffered)
153 spliceArraysLenUnsafe len s
155{-# INLINE spliceArraysRealloced #-}
156spliceArraysRealloced :: forall m a. (MonadIO m, Storable a)
157 => SerialT m (Array a) -> m (Array a)
158spliceArraysRealloced s = do
159 idst <- liftIO $ A.newArray (A.bytesToCount (undefined :: a)
162 arr <- S.foldlM' A.spliceWithDoubling idst s
163 liftIO $ A.shrinkToFit arr
165-- | Given a stream of arrays, splice them all together to generate a single
166-- array. The stream must be /finite/.
169{-# INLINE toArray #-}
170toArray :: (MonadIO m, Storable a) => SerialT m (Array a) -> m (Array a)
171toArray = spliceArraysRealloced
172-- spliceArrays = _spliceArraysBuffered
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