1{-# OPTIONS_GHC -fno-warn-orphans #-}
3{-# LANGUAGE UnboxedTuples #-}
7-- Module : Streamly.Internal.Data.Array
8-- Copyright : (c) 2019 Composewell Technologies
10-- License : BSD-3-Clause
11-- Maintainer : streamly@composewell.com
12-- Stability : pre-release
15module Streamly.Internal.Data.Array
49#if !MIN_VERSION_primitive(0,7,1)
50import Control.DeepSeq (NFData(..))
52import Control.Monad (when)
53import Control.Monad.IO.Class (liftIO, MonadIO)
54import Data.Functor.Identity (runIdentity)
55import GHC.Base (Int(..))
56import GHC.IO (unsafePerformIO)
58import Streamly.Internal.Data.Fold.Type (Fold(..))
59import Streamly.Internal.Data.Stream.StreamK.Type (IsStream)
60import Streamly.Internal.Data.Stream.Serial (SerialT)
61import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
62import Streamly.Internal.Data.Unfold.Type (Unfold(..))
64import qualified GHC.Exts as Exts
65import qualified Streamly.Internal.Data.Fold.Type as FL
66import qualified Streamly.Internal.Data.Stream.StreamD as D
68import Data.Primitive.Array hiding (fromList, fromListN)
69import Prelude hiding (foldr, length, read)
71{-# NOINLINE bottomElement #-}
73bottomElement = undefined
75-------------------------------------------------------------------------------
76-- Construction - Folds
77-------------------------------------------------------------------------------
79-- writeN n = S.evertM (fromStreamDN n)
80{-# INLINE_NORMAL writeN #-}
81writeN :: MonadIO m => Int -> Fold m a (Array a)
82writeN limit = Fold step initial extract
85 marr <- liftIO $ newArray limit bottomElement
86 return $ FL.Partial (Tuple' marr 0)
87 step st@(Tuple' marr i) x
88 | i == limit = fmap FL.Done $ extract st
90 liftIO $ writeArray marr i x
91 return $ FL.Partial $ Tuple' marr (i + 1)
92 extract (Tuple' marr len) = liftIO $ freezeArray marr 0 len
94{-# INLINE_NORMAL write #-}
95write :: MonadIO m => Fold m a (Array a)
96write = Fold step initial extract
99 marr <- liftIO $ newArray 0 bottomElement
100 return $ FL.Partial (Tuple3' marr 0 0)
101 step (Tuple3' marr i capacity) x
103 let newCapacity = max (capacity * 2) 1
104 in do newMarr <- liftIO $ newArray newCapacity bottomElement
105 liftIO $ copyMutableArray newMarr 0 marr 0 i
106 liftIO $ writeArray newMarr i x
107 return $ FL.Partial $ Tuple3' newMarr (i + 1) newCapacity
109 liftIO $ writeArray marr i x
110 return $ FL.Partial $ Tuple3' marr (i + 1) capacity
111 extract (Tuple3' marr len _) = liftIO $ freezeArray marr 0 len
113-------------------------------------------------------------------------------
114-- Construction - from streams
115-------------------------------------------------------------------------------
117{-# INLINE_NORMAL fromStreamDN #-}
118fromStreamDN :: MonadIO m => Int -> D.Stream m a -> m (Array a)
119fromStreamDN limit str = do
120 marr <- liftIO $ newArray (max limit 0) bottomElement
123 (\i x -> i `seq` liftIO $ writeArray marr i x >> return (i + 1))
126 liftIO $ freezeArray marr 0 i
128{-# INLINE fromStreamD #-}
129fromStreamD :: MonadIO m => D.Stream m a -> m (Array a)
130fromStreamD = D.fold write
132{-# INLINE fromStreamN #-}
133fromStreamN :: MonadIO m => Int -> SerialT m a -> m (Array a)
135 when (n < 0) $ error "fromStreamN: negative write count specified"
136 fromStreamDN n $ D.toStreamD m
138{-# INLINE fromStream #-}
139fromStream :: MonadIO m => SerialT m a -> m (Array a)
140fromStream m = fromStreamD $ D.toStreamD m
142{-# INLINABLE fromListN #-}
143fromListN :: Int -> [a] -> Array a
144fromListN n xs = unsafePerformIO $ fromStreamDN n $ D.fromList xs
146{-# INLINABLE fromList #-}
147fromList :: [a] -> Array a
148fromList xs = unsafePerformIO $ fromStreamD $ D.fromList xs
150-------------------------------------------------------------------------------
151-- Elimination - Unfolds
152-------------------------------------------------------------------------------
155length :: Array a -> Int
158{-# INLINE_NORMAL read #-}
159read :: Monad m => Unfold m (Array a) a
160read = Unfold step inject
162 inject arr = return (arr, 0)
164 | i == length arr = return D.Stop
167 case Exts.indexArray# (array# arr) i of
168 (# x #) -> D.Yield x (arr, I# i + 1)
170-------------------------------------------------------------------------------
171-- Elimination - to streams
172-------------------------------------------------------------------------------
174{-# INLINE_NORMAL toStreamD #-}
175toStreamD :: Monad m => Array a -> D.Stream m a
176toStreamD arr = D.Stream step 0
178 {-# INLINE_LATE step #-}
180 | i == length arr = return D.Stop
183 case Exts.indexArray# (array# arr) i of
184 (# x #) -> D.Yield x (I# i + 1)
186{-# INLINE_NORMAL toStreamDRev #-}
187toStreamDRev :: Monad m => Array a -> D.Stream m a
188toStreamDRev arr = D.Stream step (length arr - 1)
190 {-# INLINE_LATE step #-}
192 | i < 0 = return D.Stop
195 case Exts.indexArray# (array# arr) i of
196 (# x #) -> D.Yield x (I# i - 1)
198{-# INLINE_EARLY toStream #-}
199toStream :: (Monad m, IsStream t) => Array a -> t m a
200toStream = D.fromStreamD . toStreamD
202{-# INLINE_EARLY toStreamRev #-}
203toStreamRev :: (Monad m, IsStream t) => Array a -> t m a
204toStreamRev = D.fromStreamD . toStreamDRev
206-------------------------------------------------------------------------------
207-- Elimination - using Folds
208-------------------------------------------------------------------------------
210{-# INLINE_NORMAL foldl' #-}
211foldl' :: (b -> a -> b) -> b -> Array a -> b
212foldl' f z arr = runIdentity $ D.foldl' f z $ toStreamD arr
214{-# INLINE_NORMAL foldr #-}
215foldr :: (a -> b -> b) -> b -> Array a -> b
216foldr f z arr = runIdentity $ D.foldr f z $ toStreamD arr
218#if !MIN_VERSION_primitive(0,7,1)
219instance NFData a => NFData (Array a) where
221 rnf = foldl' (\_ x -> rnf x) ()
225fold :: Monad m => Fold m a b -> Array a -> m b
226fold f arr = D.fold f (toStreamD arr)
228{-# INLINE streamFold #-}
229streamFold :: Monad m => (SerialT m a -> m b) -> Array a -> m b
230streamFold f arr = f (toStream arr)
232-------------------------------------------------------------------------------
233-- Random reads and writes
234-------------------------------------------------------------------------------
236-- | /O(1)/ Lookup the element at the given index. Index starts from 0. Does
237-- not check the bounds.
240{-# INLINE getIndexUnsafe #-}
241getIndexUnsafe :: Array a -> Int -> a
242getIndexUnsafe = indexArray
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