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
53#if !MIN_VERSION_primitive(0,7,1)
54import Control.DeepSeq (NFData(..))
56import Control.Monad (when)
57import Control.Monad.IO.Class (liftIO, MonadIO)
58import Control.Monad.Primitive (PrimMonad)
59import Data.Functor.Identity (runIdentity)
61import GHC.Base (Int(..))
62import GHC.IO (unsafePerformIO)
64import Streamly.Internal.Data.Fold.Type (Fold(..))
65import Streamly.Internal.Data.Stream.Type (Stream)
66import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
67import Streamly.Internal.Data.Unfold.Type (Unfold(..))
69import qualified GHC.Exts as Exts
70import qualified Streamly.Internal.Data.Fold.Type as FL
71import qualified Streamly.Internal.Data.Ring as RB
72import qualified Streamly.Internal.Data.Stream.StreamD as D
73import qualified Streamly.Internal.Data.Stream.Type as Stream
75import Data.Primitive.Array hiding (fromList, fromListN)
76import Prelude hiding (foldr, length, read)
78{-# NOINLINE bottomElement #-}
80bottomElement = undefined
84nil = unsafePerformIO $ do
85 marr <- liftIO $ newArray 0 bottomElement
86 liftIO $ freezeArray marr 0 0
88-------------------------------------------------------------------------------
89-- Construction - Folds
90-------------------------------------------------------------------------------
92{-# INLINE_NORMAL writeN #-}
93writeN :: MonadIO m => Int -> Fold m a (Array a)
94writeN len = Fold step initial extract
103 then return $ FL.Partial st
104 else fmap FL.Done $ extract st
107 marr <- liftIO $ newArray len bottomElement
110 step (Tuple' marr i) x = do
111 liftIO $ writeArray marr i x
114 extract (Tuple' marr l) = liftIO $ freezeArray marr 0 l
116{-# INLINE_NORMAL write #-}
117write :: MonadIO m => Fold m a (Array a)
118write = Fold step initial extract
121 marr <- liftIO $ newArray 0 bottomElement
122 return $ FL.Partial (Tuple3' marr 0 0)
123 step (Tuple3' marr i capacity) x
125 let newCapacity = max (capacity * 2) 1
126 in do newMarr <- liftIO $ newArray newCapacity bottomElement
127 liftIO $ copyMutableArray newMarr 0 marr 0 i
128 liftIO $ writeArray newMarr i x
129 return $ FL.Partial $ Tuple3' newMarr (i + 1) newCapacity
131 liftIO $ writeArray marr i x
132 return $ FL.Partial $ Tuple3' marr (i + 1) capacity
133 extract (Tuple3' marr len _) = liftIO $ freezeArray marr 0 len
135-------------------------------------------------------------------------------
136-- Construction - from streams
137-------------------------------------------------------------------------------
139{-# INLINE_NORMAL fromStreamDN #-}
140fromStreamDN :: MonadIO m => Int -> D.Stream m a -> m (Array a)
141fromStreamDN limit str = do
142 marr <- liftIO $ newArray (max limit 0) bottomElement
145 (\i x -> i `seq` liftIO $ writeArray marr i x >> return (i + 1))
148 liftIO $ freezeArray marr 0 i
150{-# INLINE fromStreamD #-}
151fromStreamD :: MonadIO m => D.Stream m a -> m (Array a)
152fromStreamD = D.fold write
154{-# INLINE fromStreamN #-}
155fromStreamN :: MonadIO m => Int -> Stream m a -> m (Array a)
157 when (n < 0) $ error "fromStreamN: negative write count specified"
158 fromStreamDN n $ Stream.toStreamD m
160{-# INLINE fromStream #-}
161fromStream :: MonadIO m => Stream m a -> m (Array a)
162fromStream = fromStreamD . Stream.toStreamD
164{-# INLINABLE fromListN #-}
165fromListN :: Int -> [a] -> Array a
166fromListN n xs = unsafePerformIO $ fromStreamDN n $ D.fromList xs
168{-# INLINABLE fromList #-}
169fromList :: [a] -> Array a
170fromList xs = unsafePerformIO $ fromStreamD $ D.fromList xs
172-------------------------------------------------------------------------------
173-- Elimination - Unfolds
174-------------------------------------------------------------------------------
177length :: Array a -> Int
180{-# INLINE_NORMAL read #-}
181read :: Monad m => Unfold m (Array a) a
182read = Unfold step inject
184 inject arr = return (arr, 0)
186 | i == length arr = return D.Stop
189 case Exts.indexArray# (array# arr) i of
190 (# x #) -> D.Yield x (arr, I# i + 1)
192-------------------------------------------------------------------------------
193-- Elimination - to streams
194-------------------------------------------------------------------------------
196{-# INLINE_NORMAL toStreamD #-}
197toStreamD :: Monad m => Array a -> D.Stream m a
198toStreamD arr = D.Stream step 0
200 {-# INLINE_LATE step #-}
202 | i == length arr = return D.Stop
205 case Exts.indexArray# (array# arr) i of
206 (# x #) -> D.Yield x (I# i + 1)
208{-# INLINE_NORMAL toStreamDRev #-}
209toStreamDRev :: Monad m => Array a -> D.Stream m a
210toStreamDRev arr = D.Stream step (length arr - 1)
212 {-# INLINE_LATE step #-}
214 | i < 0 = return D.Stop
217 case Exts.indexArray# (array# arr) i of
218 (# x #) -> D.Yield x (I# i - 1)
220{-# INLINE_EARLY toStream #-}
221toStream :: Monad m => Array a -> Stream m a
222toStream = Stream.fromStreamD . toStreamD
224{-# INLINE_EARLY toStreamRev #-}
225toStreamRev :: Monad m => Array a -> Stream m a
226toStreamRev = Stream.fromStreamD . toStreamDRev
228-------------------------------------------------------------------------------
229-- Elimination - using Folds
230-------------------------------------------------------------------------------
232{-# INLINE_NORMAL foldl' #-}
233foldl' :: (b -> a -> b) -> b -> Array a -> b
234foldl' f z arr = runIdentity $ D.foldl' f z $ toStreamD arr
236{-# INLINE_NORMAL foldr #-}
237foldr :: (a -> b -> b) -> b -> Array a -> b
238foldr f z arr = runIdentity $ D.foldr f z $ toStreamD arr
240#if !MIN_VERSION_primitive(0,7,1)
241instance NFData a => NFData (Array a) where
243 rnf = foldl' (\_ x -> rnf x) ()
247fold :: Monad m => Fold m a b -> Array a -> m b
248fold f arr = D.fold f (toStreamD arr)
250{-# INLINE streamFold #-}
251streamFold :: Monad m => (Stream m a -> m b) -> Array a -> m b
252streamFold f arr = f (toStream arr)
254-------------------------------------------------------------------------------
255-- Random reads and writes
256-------------------------------------------------------------------------------
258-- | /O(1)/ Lookup the element at the given index. Index starts from 0. Does
259-- not check the bounds.
262{-# INLINE getIndexUnsafe #-}
263getIndexUnsafe :: Array a -> Int -> a
264getIndexUnsafe = indexArray
266{-# INLINE writeLastN #-}
267writeLastN :: MonadIO m => Int -> Fold m a (Array a)
269 | n <= 0 = fmap (const mempty) FL.drain
270 | otherwise = Fold step initial done
275 rb <- liftIO $ RB.createRing n
276 return $ FL.Partial $ Tuple' rb (0 :: Int)
278 step (Tuple' rb rh) x = do
279 liftIO $ RB.unsafeInsertRing rb rh x
280 return $ FL.Partial $ Tuple' rb (rh + 1)
282 done (Tuple' rb rh) = do
283 arr' <- liftIO $ newArray (min rh n) (undefined :: a)
284 ref <- liftIO $ readIORef $ RB.ringHead rb
287 liftIO $ copyMutableArray arr' 0 (RB.arr rb) 0 ref
289 liftIO $ copyMutableArray arr' 0 (RB.arr rb) ref (n - ref)
290 liftIO $ copyMutableArray arr' (n - ref) (RB.arr rb) 0 ref
291 liftIO $ unsafeFreezeArray arr'
293-- XXX This is not efficient as it copies the array. We should support array
294-- slicing so that we can just refer to the underlying array memory instead of
297-- | Truncate the array at the beginning and end as long as the predicate
299strip :: (a -> Bool) -> Array a -> Array a
301 let lastIndex = length arr - 1
302 indexR = getIndexR lastIndex -- last predicate failing index
306 let indexL = getIndexL 0 -- first predicate failing index
307 in if indexL == 0 && indexR == lastIndex
309 else cloneArray arr indexL (indexR - indexL + 1)
316 if p (indexArray arr idx) then getIndexR (idx - 1) else idx
318 getIndexL idx = if p (indexArray arr idx) then getIndexL (idx + 1) else idx
320-- | Write an input stream of (index, value) pairs to an array. Throws an
321-- error if any index is out of bounds.
324{-# INLINE putIndices #-}
325putIndices :: PrimMonad m
326 => Array a -> Fold m (Int, a) ()
327putIndices arr = FL.rmapM (\ _ -> return ()) (FL.foldlM' step initial)
331 initial = unsafeThawArray arr
333 step marr (i, x) = do
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