@@ -1,6 +1,5 @@
1{-# OPTIONS_GHC -fno-warn-orphans #-}
1{-# OPTIONS_GHC -fno-warn-orphans #-}
3−{-# LANGUAGE UnboxedTuples #-}
4#include "inline.hs"
3#include "inline.hs"
@@ -33,6 +32,7 @@ module Streamly.Internal.Data.Array
36 , toStreamD
36 , toStreamD
37 , toStreamDRev
37 , toStreamDRev
38 , toStream
38 , toStream
@@ -50,40 +50,56 @@ module Streamly.Internal.Data.Array
53−#if !MIN_VERSION_primitive(0,7,1)
54import Control.DeepSeq (NFData(..))
53import Control.DeepSeq (NFData(..))
56−import Control.Monad (when)
54+import Control.Monad (when, replicateM)
57import Control.Monad.IO.Class (liftIO, MonadIO)
55import Control.Monad.IO.Class (liftIO, MonadIO)
58−import Control.Monad.Primitive (PrimMonad)
56+import GHC.Base (MutableArray#, RealWorld)
59−import Data.Functor.Identity (runIdentity)
61−import GHC.Base (Int(..))
62import GHC.IO (unsafePerformIO)
57import GHC.IO (unsafePerformIO)
58+import Text.Read (readPrec)
64import Streamly.Internal.Data.Fold.Type (Fold(..))
60import Streamly.Internal.Data.Fold.Type (Fold(..))
65import Streamly.Internal.Data.Stream.Type (Stream)
61import Streamly.Internal.Data.Stream.Type (Stream)
66import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
62import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
67import Streamly.Internal.Data.Unfold.Type (Unfold(..))
63import Streamly.Internal.Data.Unfold.Type (Unfold(..))
69−import qualified GHC.Exts as Exts
65+import qualified Streamly.Internal.Data.Array.Mut.Type as MArray
70import qualified Streamly.Internal.Data.Fold.Type as FL
66import qualified Streamly.Internal.Data.Fold.Type as FL
71import qualified Streamly.Internal.Data.Ring as RB
67import qualified Streamly.Internal.Data.Ring as RB
72import qualified Streamly.Internal.Data.Stream.StreamD as D
68import qualified Streamly.Internal.Data.Stream.StreamD as D
73import qualified Streamly.Internal.Data.Stream.Type as Stream
69import qualified Streamly.Internal.Data.Stream.Type as Stream
70+import qualified Streamly.Internal.Data.Unfold as Unfold
71+import qualified Text.ParserCombinators.ReadPrec as ReadPrec
75−import Data.Primitive.Array hiding (fromList, fromListN)
73+import Data.IORef
76import Prelude hiding (foldr, length, read)
74import Prelude hiding (foldr, length, read)
78−{-# NOINLINE bottomElement #-}
76+-------------------------------------------------------------------------------
79−bottomElement :: a
77+-- Array Data Type
80−bottomElement = undefined
78+-------------------------------------------------------------------------------
82+ { arrContents# :: MutableArray# RealWorld a
83+ -- ^ The internal contents of the array representing the entire array.
85+ , arrStart :: {-# UNPACK #-}!Int
86+ -- ^ The starting index of this slice.
88+ , arrLen :: {-# UNPACK #-}!Int
89+ -- ^ The length of this slice.
92+unsafeFreeze :: MArray.Array a -> Array a
93+unsafeFreeze (MArray.Array cont# arrS arrL _) = Array cont# arrS arrL
95+unsafeThaw :: Array a -> MArray.Array a
96+unsafeThaw (Array cont# arrS arrL) = MArray.Array cont# arrS arrL arrL
82{-# NOINLINE nil #-}
98{-# NOINLINE nil #-}
83nil :: Array a
99nil :: Array a
84nil = unsafePerformIO $ do
100nil = unsafePerformIO $ do
85− marr <- liftIO $ newArray 0 bottomElement
101+ marr <- MArray.newArray 0
86− liftIO $ freezeArray marr 0 0
102+ return $ unsafeFreeze marr
88-------------------------------------------------------------------------------
104-------------------------------------------------------------------------------
89-- Construction - Folds
105-- Construction - Folds
@@ -91,46 +107,26 @@ nil = unsafePerformIO $ do
92{-# INLINE_NORMAL writeN #-}
108{-# INLINE_NORMAL writeN #-}
93writeN :: MonadIO m => Int -> Fold m a (Array a)
109writeN :: MonadIO m => Int -> Fold m a (Array a)
94−writeN len = Fold step initial extract
110+writeN = fmap unsafeFreeze <$> MArray.writeN
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 #-}
112{-# INLINE_NORMAL write #-}
117write :: MonadIO m => Fold m a (Array a)
113write :: MonadIO m => Fold m a (Array a)
118write = Fold step initial extract
114write = Fold step initial extract
120 initial = do
116 initial = do
121− marr <- liftIO $ newArray 0 bottomElement
117+ marr <- liftIO $ MArray.newArray 0
122 return $ FL.Partial (Tuple3' marr 0 0)
118 return $ FL.Partial (Tuple3' marr 0 0)
123 step (Tuple3' marr i capacity) x
119 step (Tuple3' marr i capacity) x
124 | i == capacity =
120 | i == capacity =
125 let newCapacity = max (capacity * 2) 1
121 let newCapacity = max (capacity * 2) 1
126− in do newMarr <- liftIO $ newArray newCapacity bottomElement
122+ in do newMarr <- liftIO $ MArray.realloc newCapacity marr
127− liftIO $ copyMutableArray newMarr 0 marr 0 i
128− liftIO $ writeArray newMarr i x
123+ marr1 <- liftIO $ MArray.snocUnsafe newMarr x
129− return $ FL.Partial $ Tuple3' newMarr (i + 1) newCapacity
124+ return $ FL.Partial $ Tuple3' marr1 (i + 1) newCapacity
130 | otherwise = do
125 | otherwise = do
131− liftIO $ writeArray marr i x
126+ marr1 <- liftIO $ MArray.snocUnsafe marr x
132− return $ FL.Partial $ Tuple3' marr (i + 1) capacity
127+ return $ FL.Partial $ Tuple3' marr1 (i + 1) capacity
133− extract (Tuple3' marr len _) = liftIO $ freezeArray marr 0 len
128+ extract (Tuple3' marr _ _) =
129+ return $ unsafeFreeze marr
135-------------------------------------------------------------------------------
131-------------------------------------------------------------------------------
136-- Construction - from streams
132-- Construction - from streams
@@ -139,13 +135,13 @@ write = Fold step initial extract
139{-# INLINE_NORMAL fromStreamDN #-}
135{-# INLINE_NORMAL fromStreamDN #-}
140fromStreamDN :: MonadIO m => Int -> D.Stream m a -> m (Array a)
136fromStreamDN :: MonadIO m => Int -> D.Stream m a -> m (Array a)
141fromStreamDN limit str = do
137fromStreamDN limit str = do
142− marr <- liftIO $ newArray (max limit 0) bottomElement
138+ marr <- liftIO $ MArray.newArray (max limit 0)
144 D.foldlM'
140 D.foldlM'
145− (\i x -> i `seq` liftIO $ writeArray marr i x >> return (i + 1))
141+ (\i x -> i `seq` liftIO $ MArray.putIndexUnsafe marr i x >> return (i + 1))
146 (return 0) $
142 (return 0) $
147 D.take limit str
143 D.take limit str
148− liftIO $ freezeArray marr 0 i
144+ return $ unsafeFreeze $ marr { MArray.arrLen = i }
150{-# INLINE fromStreamD #-}
146{-# INLINE fromStreamD #-}
151fromStreamD :: MonadIO m => D.Stream m a -> m (Array a)
147fromStreamD :: MonadIO m => D.Stream m a -> m (Array a)
@@ -175,50 +171,38 @@ fromList xs = unsafePerformIO $ fromStreamD $ D.fromList xs
176{-# INLINE length #-}
172{-# INLINE length #-}
177length :: Array a -> Int
173length :: Array a -> Int
178−length = sizeofArray
174+length = arrLen
180{-# INLINE_NORMAL read #-}
176{-# INLINE_NORMAL read #-}
181−read :: Monad m => Unfold m (Array a) a
177+read :: MonadIO m => Unfold m (Array a) a
182−read = Unfold step inject
178+read = Unfold.lmap unsafeThaw MArray.read
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-------------------------------------------------------------------------------
180-------------------------------------------------------------------------------
193-- Elimination - to streams
181-- Elimination - to streams
194-------------------------------------------------------------------------------
182-------------------------------------------------------------------------------
184+{-# INLINE_NORMAL toList #-}
185+toList :: Array a -> [a]
191+ loop i | i == len = []
192+ loop i = getIndexUnsafe arr i : loop (i + 1)
196{-# INLINE_NORMAL toStreamD #-}
194{-# INLINE_NORMAL toStreamD #-}
197−toStreamD :: Monad m => Array a -> D.Stream m a
195+toStreamD :: MonadIO m => Array a -> D.Stream m a
198−toStreamD arr = D.Stream step 0
196+toStreamD = MArray.toStreamD . unsafeThaw
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 #-}
198{-# INLINE_NORMAL toStreamDRev #-}
209toStreamDRev :: Monad m => Array a -> D.Stream m a
199toStreamDRev :: Monad m => Array a -> D.Stream m a
210−toStreamDRev arr = D.Stream step (length arr - 1)
200+toStreamDRev arr@Array{..} =
211− where
201+ D.map (getIndexUnsafe arr)
212− {-# INLINE_LATE step #-}
202+ $ D.enumerateFromThenToIntegral (arrLen - 1) (arrLen - 2) 0
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 #-}
204{-# INLINE_EARLY toStream #-}
221−toStream :: Monad m => Array a -> Stream m a
205+toStream :: MonadIO m => Array a -> Stream m a
222toStream = Stream.fromStreamD . toStreamD
206toStream = Stream.fromStreamD . toStreamD
224{-# INLINE_EARLY toStreamRev #-}
208{-# INLINE_EARLY toStreamRev #-}
@@ -231,24 +215,22 @@ toStreamRev = Stream.fromStreamD . toStreamDRev
232{-# INLINE_NORMAL foldl' #-}
216{-# INLINE_NORMAL foldl' #-}
233foldl' :: (b -> a -> b) -> b -> Array a -> b
217foldl' :: (b -> a -> b) -> b -> Array a -> b
234−foldl' f z arr = runIdentity $ D.foldl' f z $ toStreamD arr
218+foldl' f z arr = unsafePerformIO $ D.foldl' f z $ toStreamD arr
236{-# INLINE_NORMAL foldr #-}
220{-# INLINE_NORMAL foldr #-}
237foldr :: (a -> b -> b) -> b -> Array a -> b
221foldr :: (a -> b -> b) -> b -> Array a -> b
238−foldr f z arr = runIdentity $ D.foldr f z $ toStreamD arr
222+foldr f z arr = unsafePerformIO $ D.foldr f z $ toStreamD arr
240−#if !MIN_VERSION_primitive(0,7,1)
241instance NFData a => NFData (Array a) where
224instance NFData a => NFData (Array a) where
242 {-# INLINE rnf #-}
225 {-# INLINE rnf #-}
243 rnf = foldl' (\_ x -> rnf x) ()
226 rnf = foldl' (\_ x -> rnf x) ()
246{-# INLINE fold #-}
228{-# INLINE fold #-}
247−fold :: Monad m => Fold m a b -> Array a -> m b
229+fold :: MonadIO m => Fold m a b -> Array a -> m b
248fold f arr = D.fold f (toStreamD arr)
230fold f arr = D.fold f (toStreamD arr)
250{-# INLINE streamFold #-}
232{-# INLINE streamFold #-}
251−streamFold :: Monad m => (Stream m a -> m b) -> Array a -> m b
233+streamFold :: MonadIO m => (Stream m a -> m b) -> Array a -> m b
252streamFold f arr = f (toStream arr)
234streamFold f arr = f (toStream arr)
254-------------------------------------------------------------------------------
236-------------------------------------------------------------------------------
@@ -261,12 +243,13 @@ streamFold f arr = f (toStream arr)
261-- @since 0.8.0
243-- @since 0.8.0
262{-# INLINE getIndexUnsafe #-}
244{-# INLINE getIndexUnsafe #-}
263getIndexUnsafe :: Array a -> Int -> a
245getIndexUnsafe :: Array a -> Int -> a
264−getIndexUnsafe = indexArray
246+getIndexUnsafe arr i =
247+ unsafePerformIO $ MArray.getIndexUnsafe (unsafeThaw arr) i
266{-# INLINE writeLastN #-}
249{-# INLINE writeLastN #-}
267writeLastN :: MonadIO m => Int -> Fold m a (Array a)
250writeLastN :: MonadIO m => Int -> Fold m a (Array a)
268writeLastN n
251writeLastN n
269− | n <= 0 = fmap (const mempty) FL.drain
252+ | n <= 0 = fmap (const nil) FL.drain
270 | otherwise = Fold step initial done
253 | otherwise = Fold step initial done
@@ -280,15 +263,18 @@ writeLastN n
280 return $ FL.Partial $ Tuple' rb (rh + 1)
263 return $ FL.Partial $ Tuple' rb (rh + 1)
282 done (Tuple' rb rh) = do
265 done (Tuple' rb rh) = do
283− arr' <- liftIO $ newArray (min rh n) (undefined :: a)
266+ arr' <- liftIO $ MArray.newArray (min rh n)
284 ref <- liftIO $ readIORef $ RB.ringHead rb
267 ref <- liftIO $ readIORef $ RB.ringHead rb
285 if rh < n
268 if rh < n
287− liftIO $ copyMutableArray arr' 0 (RB.arr rb) 0 ref
270+ MArray.putSliceUnsafe (RB.arr rb) 0 arr' 0 ref
289− liftIO $ copyMutableArray arr' 0 (RB.arr rb) ref (n - ref)
272+ MArray.putSliceUnsafe (RB.arr rb) ref arr' 0 (n - ref)
290− liftIO $ copyMutableArray arr' (n - ref) (RB.arr rb) 0 ref
273+ MArray.putSliceUnsafe (RB.arr rb) 0 arr' (n - ref) ref
291− liftIO $ unsafeFreezeArray arr'
274+ return $ unsafeFreeze arr'
276+sliceUnsafe :: Int -> Int -> Array a -> Array a
277+sliceUnsafe offset len (Array cont off1 _) = Array cont (off1 + offset) len
293-- XXX This is not efficient as it copies the array. We should support array
279-- 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
280-- slicing so that we can just refer to the underlying array memory instead of
@@ -306,30 +292,86 @@ strip p arr =
306 let indexL = getIndexL 0 -- first predicate failing index
292 let indexL = getIndexL 0 -- first predicate failing index
307 in if indexL == 0 && indexR == lastIndex
293 in if indexL == 0 && indexR == lastIndex
295+ else unsafeFreeze $ unsafePerformIO $ do
309− else cloneArray arr indexL (indexR - indexL + 1)
296+ let newLen = indexR - indexL + 1
297+ arrThawed = unsafeThaw (sliceUnsafe indexL newLen arr)
298+ MArray.clone arrThawed
313 getIndexR idx
302 getIndexR idx
314 | idx < 0 = idx
303 | idx < 0 = idx
315 | otherwise =
304 | otherwise =
316− if p (indexArray arr idx) then getIndexR (idx - 1) else idx
305+ if p (getIndexUnsafe arr idx) then getIndexR (idx - 1) else idx
307+ getIndexL idx = if p (getIndexUnsafe arr idx)
318− getIndexL idx = if p (indexArray arr idx) then getIndexL (idx + 1) else idx
308+ then getIndexL (idx + 1)
320-- | Write an input stream of (index, value) pairs to an array. Throws an
311-- | Write an input stream of (index, value) pairs to an array. Throws an
321-- error if any index is out of bounds.
312-- error if any index is out of bounds.
323-- /Pre-release/
314-- /Pre-release/
324{-# INLINE putIndices #-}
315{-# INLINE putIndices #-}
325−putIndices :: PrimMonad m
316+putIndices :: MonadIO m
326 => Array a -> Fold m (Int, a) ()
317 => Array a -> Fold m (Int, a) ()
327putIndices arr = FL.rmapM (\ _ -> return ()) (FL.foldlM' step initial)
318putIndices arr = FL.rmapM (\ _ -> return ()) (FL.foldlM' step initial)
331− initial = unsafeThawArray arr
322+ initial = return $ unsafeThaw arr
333 step marr (i, x) = do
324 step marr (i, x) = do
334− writeArray marr i x
325+ MArray.putIndexUnsafe marr i x
335 return marr
326 return marr
328+-------------------------------------------------------------------------------
330+-------------------------------------------------------------------------------
332+instance Eq a => Eq (Array a) where
333+ a1 == a2 = lenA1 == lenA2 && loop (lenA1 - 1)
343+ let v1 = getIndexUnsafe a1 i
344+ v2 = getIndexUnsafe a2 i
345+ in v1 == v2 && loop (i - 1)
347+instance Ord a => Ord (Array a) where
349+ case compare lenA1 lenA2 of
362+ let v1 = getIndexUnsafe a1 i
363+ v2 = getIndexUnsafe a2 i
364+ in case compare v1 v2 of
369+instance Show a => Show (Array a) where
370+ show arr = "fromList " ++ show (toList arr)
372+instance Read a => Read (Array a) where
374+ fromListWord <- replicateM 9 ReadPrec.get
375+ if fromListWord == "fromList "
376+ then fromList <$> readPrec