@@ -23,6 +23,7 @@ module Streamly.Memory.Ring
2323 , unsafeFoldRing
2424 , unsafeFoldRingM
2525 , unsafeFoldRingFullM
26+ , unsafeFoldRingNM
2627
2728 -- * Fast Byte Comparisons
2829 , unsafeEqArray
@@ -209,6 +210,9 @@ unsafeFoldRingM ptr f z Ring {..} =
209210-- pointer. Assuming the supplied ringHead pointer points to the oldest item,
210211-- this would fold the ring starting from the oldest item to the newest item in
211212-- the ring.
213+--
214+-- Note, this will crash on ring of 0 size.
215+--
212216{-# INLINE unsafeFoldRingFullM #-}
213217unsafeFoldRingFullM :: forall m a b. (MonadIO m, Storable a)
214218 => Ptr a -> (b -> a -> m b) -> b -> Ring a -> m b
@@ -222,3 +226,25 @@ unsafeFoldRingFullM rh f z rb@Ring {..} =
222226 if ptr == rh
223227 then return acc'
224228 else go acc' ptr
229+
230+-- | Fold @Int@ items in the ring starting at @Ptr a@. Won't fold more
231+-- than the length of the ring.
232+--
233+-- Note, this will crash on ring of 0 size.
234+--
235+{-# INLINE unsafeFoldRingNM #-}
236+unsafeFoldRingNM :: forall m a b. (MonadIO m, Storable a)
237+ => Int -> Ptr a -> (b -> a -> m b) -> b -> Ring a -> m b
238+unsafeFoldRingNM count rh f z rb@Ring {..} =
239+ withForeignPtrM ringStart $ \_ -> go count z rh
240+
241+ where
242+
243+ go 0 acc _ = return acc
244+ go !n !acc !start = do
245+ let !x = A.unsafeInlineIO $ peek start
246+ acc' <- f acc x
247+ let ptr = advance rb start
248+ if ptr == rh || n == 0
249+ then return acc'
250+ else go (n - 1) acc' ptr