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
52#if !MIN_VERSION_primitive(0,7,1)
53import Control.DeepSeq (NFData(..))
55import Control.Monad (when)
56import Control.Monad.IO.Class (liftIO, MonadIO)
57import Data.Functor.Identity (runIdentity)
59import GHC.Base (Int(..))
60import GHC.IO (unsafePerformIO)
62import Streamly.Internal.Data.Fold.Type (Fold(..))
63import Streamly.Internal.Data.Stream.Serial (SerialT(..))
64import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
65import Streamly.Internal.Data.Unfold.Type (Unfold(..))
67import qualified GHC.Exts as Exts
68import qualified Streamly.Internal.Data.Fold.Type as FL
69import qualified Streamly.Internal.Data.Ring as RB
70import qualified Streamly.Internal.Data.Stream.StreamD as D
72import Data.Primitive.Array hiding (fromList, fromListN)
73import Prelude hiding (foldr, length, read)
75{-# NOINLINE bottomElement #-}
77bottomElement = undefined
81nil = unsafePerformIO $ do
82 marr <- liftIO $ newArray 0 bottomElement
83 liftIO $ freezeArray marr 0 0
85-------------------------------------------------------------------------------
86-- Construction - Folds
87-------------------------------------------------------------------------------
89{-# INLINE_NORMAL writeN #-}
90writeN :: MonadIO m => Int -> Fold m a (Array a)
91writeN len = Fold step initial extract
100 then return $ FL.Partial st
101 else fmap FL.Done $ extract st
104 marr <- liftIO $ newArray len bottomElement
107 step (Tuple' marr i) x = do
108 liftIO $ writeArray marr i x
111 extract (Tuple' marr l) = liftIO $ freezeArray marr 0 l
113{-# INLINE_NORMAL write #-}
114write :: MonadIO m => Fold m a (Array a)
115write = Fold step initial extract
118 marr <- liftIO $ newArray 0 bottomElement
119 return $ FL.Partial (Tuple3' marr 0 0)
120 step (Tuple3' marr i capacity) x
122 let newCapacity = max (capacity * 2) 1
123 in do newMarr <- liftIO $ newArray newCapacity bottomElement
124 liftIO $ copyMutableArray newMarr 0 marr 0 i
125 liftIO $ writeArray newMarr i x
126 return $ FL.Partial $ Tuple3' newMarr (i + 1) newCapacity
128 liftIO $ writeArray marr i x
129 return $ FL.Partial $ Tuple3' marr (i + 1) capacity
130 extract (Tuple3' marr len _) = liftIO $ freezeArray marr 0 len
132-------------------------------------------------------------------------------
133-- Construction - from streams
134-------------------------------------------------------------------------------
136{-# INLINE_NORMAL fromStreamDN #-}
137fromStreamDN :: MonadIO m => Int -> D.Stream m a -> m (Array a)
138fromStreamDN limit str = do
139 marr <- liftIO $ newArray (max limit 0) bottomElement
142 (\i x -> i `seq` liftIO $ writeArray marr i x >> return (i + 1))
145 liftIO $ freezeArray marr 0 i
147{-# INLINE fromStreamD #-}
148fromStreamD :: MonadIO m => D.Stream m a -> m (Array a)
149fromStreamD = D.fold write
151{-# INLINE fromStreamN #-}
152fromStreamN :: MonadIO m => Int -> SerialT m a -> m (Array a)
153fromStreamN n (SerialT m) = do
154 when (n < 0) $ error "fromStreamN: negative write count specified"
155 fromStreamDN n $ D.fromStreamK m
157{-# INLINE fromStream #-}
158fromStream :: MonadIO m => SerialT m a -> m (Array a)
159fromStream (SerialT m) = fromStreamD $ D.fromStreamK m
161{-# INLINABLE fromListN #-}
162fromListN :: Int -> [a] -> Array a
163fromListN n xs = unsafePerformIO $ fromStreamDN n $ D.fromList xs
165{-# INLINABLE fromList #-}
166fromList :: [a] -> Array a
167fromList xs = unsafePerformIO $ fromStreamD $ D.fromList xs
169-------------------------------------------------------------------------------
170-- Elimination - Unfolds
171-------------------------------------------------------------------------------
174length :: Array a -> Int
177{-# INLINE_NORMAL read #-}
178read :: Monad m => Unfold m (Array a) a
179read = Unfold step inject
181 inject arr = return (arr, 0)
183 | i == length arr = return D.Stop
186 case Exts.indexArray# (array# arr) i of
187 (# x #) -> D.Yield x (arr, I# i + 1)
189-------------------------------------------------------------------------------
190-- Elimination - to streams
191-------------------------------------------------------------------------------
193{-# INLINE_NORMAL toStreamD #-}
194toStreamD :: Monad m => Array a -> D.Stream m a
195toStreamD arr = D.Stream step 0
197 {-# INLINE_LATE step #-}
199 | i == length arr = return D.Stop
202 case Exts.indexArray# (array# arr) i of
203 (# x #) -> D.Yield x (I# i + 1)
205{-# INLINE_NORMAL toStreamDRev #-}
206toStreamDRev :: Monad m => Array a -> D.Stream m a
207toStreamDRev arr = D.Stream step (length arr - 1)
209 {-# INLINE_LATE step #-}
211 | i < 0 = return D.Stop
214 case Exts.indexArray# (array# arr) i of
215 (# x #) -> D.Yield x (I# i - 1)
217{-# INLINE_EARLY toStream #-}
218toStream :: Monad m => Array a -> SerialT m a
219toStream = SerialT . D.toStreamK . toStreamD
221{-# INLINE_EARLY toStreamRev #-}
222toStreamRev :: Monad m => Array a -> SerialT m a
223toStreamRev = SerialT . D.toStreamK . toStreamDRev
225-------------------------------------------------------------------------------
226-- Elimination - using Folds
227-------------------------------------------------------------------------------
229{-# INLINE_NORMAL foldl' #-}
230foldl' :: (b -> a -> b) -> b -> Array a -> b
231foldl' f z arr = runIdentity $ D.foldl' f z $ toStreamD arr
233{-# INLINE_NORMAL foldr #-}
234foldr :: (a -> b -> b) -> b -> Array a -> b
235foldr f z arr = runIdentity $ D.foldr f z $ toStreamD arr
237#if !MIN_VERSION_primitive(0,7,1)
238instance NFData a => NFData (Array a) where
240 rnf = foldl' (\_ x -> rnf x) ()
244fold :: Monad m => Fold m a b -> Array a -> m b
245fold f arr = D.fold f (toStreamD arr)
247{-# INLINE streamFold #-}
248streamFold :: Monad m => (SerialT m a -> m b) -> Array a -> m b
249streamFold f arr = f (toStream arr)
251-------------------------------------------------------------------------------
252-- Random reads and writes
253-------------------------------------------------------------------------------
255-- | /O(1)/ Lookup the element at the given index. Index starts from 0. Does
256-- not check the bounds.
259{-# INLINE getIndexUnsafe #-}
260getIndexUnsafe :: Array a -> Int -> a
261getIndexUnsafe = indexArray
263{-# INLINE writeLastN #-}
264writeLastN :: MonadIO m => Int -> Fold m a (Array a)
266 | n <= 0 = fmap (const mempty) FL.drain
267 | otherwise = Fold step initial done
272 rb <- liftIO $ RB.createRing n
273 return $ FL.Partial $ Tuple' rb (0 :: Int)
275 step (Tuple' rb rh) x = do
276 liftIO $ RB.unsafeInsertRing rb rh x
277 return $ FL.Partial $ Tuple' rb (rh + 1)
279 done (Tuple' rb rh) = do
280 arr' <- liftIO $ newArray (min rh n) (undefined :: a)
281 ref <- liftIO $ readIORef $ RB.ringHead rb
284 liftIO $ copyMutableArray arr' 0 (RB.arr rb) 0 ref
286 liftIO $ copyMutableArray arr' 0 (RB.arr rb) ref (n - ref)
287 liftIO $ copyMutableArray arr' (n - ref) (RB.arr rb) 0 ref
288 liftIO $ unsafeFreezeArray arr'
290-- XXX This is not efficient as it copies the array. We should support array
291-- slicing so that we can just refer to the underlying array memory instead of
294-- | Truncate the array at the beginning and end as long as the predicate
296strip :: (a -> Bool) -> Array a -> Array a
298 let lastIndex = length arr - 1
299 indexR = getIndexR lastIndex -- last predicate failing index
303 let indexL = getIndexL 0 -- first predicate failing index
304 in if indexL == 0 && indexR == lastIndex
306 else cloneArray arr indexL (indexR - indexL + 1)
313 if p (indexArray arr idx) then getIndexR (idx - 1) else idx
315 getIndexL idx = if p (indexArray arr idx) then getIndexL (idx + 1) else idx
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