@@ -18,6 +18,7 @@ module Streamly.Internal.Data.Array
1818 -- * Construction
1919 , writeN
2020 , write
21+ , writeLastN
2122
2223 , fromStreamDN
2324 , fromStreamD
@@ -52,6 +53,7 @@ import Control.DeepSeq (NFData(..))
5253import Control.Monad (when)
5354import Control.Monad.IO.Class (liftIO, MonadIO)
5455import Data.Functor.Identity (runIdentity)
56+import Data.IORef
5557import GHC.Base (Int(..))
5658import GHC.IO (unsafePerformIO)
5759
@@ -62,6 +64,7 @@ import Streamly.Internal.Data.Unfold.Type (Unfold(..))
6264
6365import qualified GHC.Exts as Exts
6466import qualified Streamly.Internal.Data.Fold.Type as FL
67+import qualified Streamly.Internal.Data.Ring as RB
6568import qualified Streamly.Internal.Data.Stream.StreamD as D
6669
6770import Data.Primitive.Array hiding (fromList, fromListN)
@@ -248,3 +251,30 @@ streamFold f arr = f (toStream arr)
248251{-# INLINE getIndexUnsafe #-}
249252getIndexUnsafe :: Array a -> Int -> a
250253getIndexUnsafe = indexArray
254+
255+{-# INLINE writeLastN #-}
256+writeLastN :: MonadIO m => Int -> Fold m a (Array a)
257+writeLastN n
258+ | n <= 0 = fmap (const mempty) FL.drain
259+ | otherwise = Fold step initial done
260+
261+ where
262+
263+ initial = do
264+ rb <- liftIO $ RB.createRing n
265+ return $ FL.Partial $ Tuple' rb (0 :: Int)
266+
267+ step (Tuple' rb rh) x = do
268+ liftIO $ RB.unsafeInsertRing rb rh x
269+ return $ FL.Partial $ Tuple' rb (rh + 1)
270+
271+ done (Tuple' rb rh) = do
272+ arr' <- liftIO $ newArray (min rh n) (undefined :: a)
273+ ref <- liftIO $ readIORef $ RB.ringHead rb
274+ if rh < n
275+ then
276+ liftIO $ copyMutableArray arr' 0 (RB.arr rb) 0 ref
277+ else do
278+ liftIO $ copyMutableArray arr' 0 (RB.arr rb) ref (n - ref)
279+ liftIO $ copyMutableArray arr' (n - ref) (RB.arr rb) 0 ref
280+ liftIO $ unsafeFreezeArray arr'