@@ -20,6 +20,7 @@ module Streamly.Internal.Data.Ring.Generic
2020
2121 -- * Conversion
2222 , toMutArray
23+ , copyToMutArray
2324 , toStreamWith
2425 ) where
2526
@@ -29,15 +30,11 @@ import Control.Monad.IO.Class (liftIO, MonadIO)
2930import Streamly.Internal.Data.Stream.Type (Stream)
3031import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
3132import Streamly.Internal.Data.Fold.Type (Fold(..))
32−import Streamly.Internal.Data.MutArray.Generic
33− ( MutArray(..)
34− , new
35− , uninit
36− , putIndexUnsafe
37− , putSliceUnsafe
38− )
33+import Streamly.Internal.Data.MutArray.Generic (MutArray(..))
34+
3935-- import qualified Streamly.Internal.Data.Stream.Type as Stream
4036import qualified Streamly.Internal.Data.Fold.Type as Fold
37+import qualified Streamly.Internal.Data.MutArray.Generic as MutArray
4138
4239-- XXX Use MutableArray rather than keeping a MutArray here.
4340data Ring a = Ring
@@ -58,8 +55,8 @@ data Ring a = Ring
5855{-# INLINE createRing #-}
5956createRing :: MonadIO m => Int -> m (Ring a)
6057createRing count = liftIO $ do
61− arr <- new count
62− arr1 <- uninit arr count
58+ arr <- MutArray.new count
59+ arr1 <- MutArray.uninit arr count
6360 return (Ring
6461 { ringArr = arr1
6562 , ringHead = 0
@@ -67,6 +64,9 @@ createRing count = liftIO $ do
6764 })
6865
6966
67+-- | Note that it is not safe to return a reference to the mutable Ring using a
68+-- scan as the Ring is continuously getting mutated. You could however copy out
69+-- the Ring.
7070{-# INLINE writeLastN #-}
7171writeLastN :: MonadIO m => Int -> Fold m a (Ring a)
7272writeLastN n = Fold step initial extract
@@ -101,7 +101,7 @@ unsafeInsertRingWith :: Ring a -> a -> IO Int
101101unsafeInsertRingWith Ring{..} x = do
102102 assertM(ringMax >= 1)
103103 assertM(ringHead < ringMax)
104− putIndexUnsafe ringHead ringArr x
104+ MutArray.putIndexUnsafe ringHead ringArr x
105105 let rh1 = ringHead + 1
106106 next = if rh1 == ringMax then 0 else rh1
107107 return next
@@ -124,24 +124,45 @@ seek adj rng@Ring{..}
124124
125125-- | @toMutArray rignHeadAdjustment lengthToRead ring@.
126126-- Convert the ring into a boxed mutable array. Note that the returned MutArray
127−-- may share the same underlying memory as the Ring.
127+-- shares the same underlying memory as the Ring, the user of this API needs to
128+-- ensure that the ring is not mutated during and after the conversion.
129+--
128130{-# INLINE toMutArray #-}
129131toMutArray :: MonadIO m => Int -> Int -> Ring a -> m (MutArray a)
130−toMutArray adj n Ring{..} = do
131− let len = min ringMax n
132− let idx = mod (ringHead + adj) ringMax
133− end = idx + len
134− if end <= ringMax
135− then
136− -- putSliceUnsafe ringArr idx arr1 0 len
137− return $ ringArr { arrStart = idx, arrLen = len }
132+toMutArray adj n Ring{..} =
133+ -- XXX for empty Ring it will raise an Exception: divide by zero
134+ if ringMax <= 0
135+ then MutArray.nil
136+ else do
137+ let len = min ringMax n
138+ let idx = mod (ringHead + adj) ringMax
139+ end = idx + len
140+ if end <= ringMax
141+ then
142+ return $ ringArr { arrStart = idx, arrLen = len }
143+ else do
144+ -- XXX Just swap the elements in the existing ring and return the
145+ -- same array without reallocation.
146+ arr <- liftIO $ MutArray.new len
147+ arr1 <- MutArray.uninit arr len
148+ MutArray.putSliceUnsafe ringArr idx arr1 0 (ringMax - idx)
149+ MutArray.putSliceUnsafe ringArr 0 arr1 (ringMax - idx) (end - ringMax)
150+ return arr1
151+
152+-- | Copy out the mutable ring to a mutable Array.
153+{-# INLINE copyToMutArray #-}
154+copyToMutArray :: MonadIO m => Int -> Int -> Ring a -> m (MutArray a)
155+copyToMutArray adj n Ring{..} = do
156+ if ringMax <= 0
157+ then MutArray.nil
138158 else do
139− -- XXX Just swap the elements in the existing ring and return the
140− -- same array without reallocation.
141− arr <- liftIO $ new len
142− arr1 <- uninit arr len
143− putSliceUnsafe ringArr idx arr1 0 (ringMax - idx)
144− putSliceUnsafe ringArr 0 arr1 (ringMax - idx) (end - ringMax)
159+ let len = min ringMax n
160+ let idx = mod (ringHead + adj) ringMax
161+ end = idx + len
162+ arr <- MutArray.new len
163+ arr1 <- MutArray.uninit arr len
164+ MutArray.putSliceUnsafe ringArr idx arr1 0 (ringMax - idx)
165+ MutArray.putSliceUnsafe ringArr 0 arr1 (ringMax - idx) (end - ringMax)
145166 return arr1
146167
147168-- This would be theoretically slower than toMutArray because of a branch