1-- Copyright : (c) 2020 Composewell Technologies
2-- License : BSD-3-Clause
3-- Maintainer : streamly@composewell.com
4-- Stability : experimental
7import Control.Monad (when)
8import Control.Monad.IO.Class (MonadIO(..))
9import Data.Primitive.Types (Prim(..))
10import Streamly.Internal.Data.Fold.Type (Fold(..))
11import Streamly.Internal.Data.Unfold.Type (Unfold(..))
12import Streamly.Internal.Data.Stream.Serial (SerialT(..))
14import qualified Streamly.Internal.Data.Stream.Prelude as P
15import qualified Streamly.Internal.Data.Stream.StreamD as D
17import Prelude hiding (length, null, last, map, (!!), read, concat)
19-------------------------------------------------------------------------------
21-------------------------------------------------------------------------------
23-- | Create an 'Array' from the first N elements of a stream. The array is
24-- allocated to size N, if the stream terminates before N elements then the
25-- array may hold less than N elements.
28{-# INLINE fromStreamN #-}
29fromStreamN :: (MonadIO m, Prim a) => Int -> SerialT m a -> m (Array a)
30fromStreamN n (SerialT m) = do
31 when (n < 0) $ error "writeN: negative write count specified"
32 A.fromStreamDN n $ D.fromStreamK m
34-- | Create an 'Array' from a stream. This is useful when we want to create a
35-- single array from a stream of unknown size. 'writeN' is at least twice
36-- as efficient when the size is already known.
38-- Note that if the input stream is too large memory allocation for the array
39-- may fail. When the stream size is not known, `arraysOf` followed by
40-- processing of indvidual arrays in the resulting stream should be preferred.
43{-# INLINE fromStream #-}
44fromStream :: (MonadIO m, Prim a) => SerialT m a -> m (Array a)
45fromStream (SerialT m) = P.fold A.write m
46-- write m = A.fromStreamD $ D.toStreamD m
48-------------------------------------------------------------------------------
50-------------------------------------------------------------------------------
52-- | Convert an 'Array' into a stream.
55{-# INLINE_EARLY toStream #-}
56toStream :: (MonadIO m, Prim a) => Array a -> SerialT m a
57toStream = SerialT . D.toStreamK . A.toStreamD
58-- XXX add fallback to StreamK rule
59-- {-# RULES "Streamly.Array.read fallback to StreamK" [1]
60-- forall a. S.readK (read a) = K.fromArray a #-}
62-- | Convert an 'Array' into a stream in reverse order.
65{-# INLINE_EARLY toStreamRev #-}
66toStreamRev :: (MonadIO m, Prim a) => Array a -> SerialT m a
67toStreamRev = SerialT . D.toStreamK . A.toStreamDRev
68-- XXX add fallback to StreamK rule
69-- {-# RULES "Streamly.Array.readRev fallback to StreamK" [1]
70-- forall a. S.toStreamK (readRev a) = K.revFromArray a #-}
72-- | Unfold an array into a stream.
75{-# INLINE_NORMAL read #-}
76read :: (MonadIO m, Prim a) => Unfold m (Array a) a
77read = Unfold step inject
82 {-# INLINE_LATE step #-}
83 step (Array _ _ len) | len == 0 = return D.Stop
84 step arr@(Array arr# off len) =
85 let !x = A.unsafeIndex arr 0
86 in return $ D.Yield x (Array arr# (off + 1) (len - 1))
88-- | Unfold an array into a stream, does not check the end of the array, the
89-- user is responsible for terminating the stream within the array bounds. For
90-- high performance application where the end condition can be determined by
93-- The following might not be true, not that the representation changed.
94-- Written in the hope that it may be faster than "read", however, in the case
95-- for which this was written, "read" proves to be faster even though the core
96-- generated with unsafeRead looks simpler.
100{-# INLINE_NORMAL unsafeRead #-}
101unsafeRead :: (MonadIO m, Prim a) => Unfold m (Array a) a
102unsafeRead = Unfold step inject
107 {-# INLINE_LATE step #-}
108 step arr@(Array arr# off len) =
109 let !x = A.unsafeIndex arr 0
110 in return $ D.Yield x (Array arr# (off + 1) (len - 1))
112-- | > null arr = length arr == 0
116null :: Array a -> Bool
117null arr = length arr == 0
119-------------------------------------------------------------------------------
121-------------------------------------------------------------------------------
123-- | Fold an array using a 'Fold'.
127fold :: forall m a b. (MonadIO m, Prim a) => Fold m a b -> Array a -> m b
128fold f arr = P.fold f (getSerialT (toStream arr))
130-- | Fold an array using a stream fold operation.
133{-# INLINE streamFold #-}
134streamFold :: (MonadIO m, Prim a) => (SerialT m a -> m b) -> Array a -> m b
135streamFold f arr = f (toStream arr)
137-------------------------------------------------------------------------------
139-------------------------------------------------------------------------------
141-- | /O(1)/ Lookup the element at the given index, starting from 0.
144{-# INLINE readIndex #-}
145readIndex :: Prim a => Array a -> Int -> Maybe a
147 if i < 0 || i > length arr - 1
149 else Just $ A.unsafeIndex arr i
151-- | > last arr = readIndex arr (length arr - 1)
155last :: Prim a => Array a -> Maybe a
156last arr = readIndex arr (length arr - 1)
158-------------------------------------------------------------------------------
159-- Array stream operations
160-------------------------------------------------------------------------------
162-- | Convert a stream of arrays into a stream of their elements.
164-- Same as the following but more efficient:
166-- > concat = S.concatMap A.read
170concat :: (MonadIO m, Prim a) => SerialT m (Array a) -> SerialT m a
171-- concat m = D.fromStreamD $ A.flattenArrays (D.toStreamD m)
172-- concat m = D.fromStreamD $ D.concatMap A.toStreamD (D.toStreamD m)
174 SerialT $ D.toStreamK $ D.unfoldMany read (D.fromStreamK m)
176-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
177-- maximum specified size in bytes.
180{-# INLINE compact #-}
182 (MonadIO m, Prim a) => Int -> SerialT m (Array a) -> SerialT m (Array a)
183compact n (SerialT xs) =
184 SerialT $ D.toStreamK $ A.packArraysChunksOf n (D.fromStreamK xs)
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