@@ -269,6 +269,8 @@ module Streamly.Internal.Data.Fold
269269 , snoc
270270 , duplicate
271271 , finish
272+ , top
273+ , bottom
272274
273275 -- * Deprecated
274276 , sequence
@@ -286,6 +288,7 @@ import Data.Int (Int64)
286288import Data.IORef (newIORef, readIORef, writeIORef)
287289import Data.Map.Strict (Map)
288290import Data.Maybe (isJust, fromJust)
291+import Foreign.Storable (Storable)
289292import Streamly.Internal.Data.IsMap (IsMap(..))
290293import Streamly.Internal.Data.Pipe.Type (Pipe (..), PipeState(..))
291294import Streamly.Internal.Data.Unfold.Type (Unfold(..))
@@ -296,6 +299,7 @@ import qualified Data.IntSet as IntSet
296299import qualified Data.Set as Set
297300import qualified Streamly.Internal.Data.IsMap as IsMap
298301import qualified Prelude
302+import qualified Streamly.Internal.Data.Array.Foreign.Mut.Type as MA
299303import qualified Streamly.Internal.Data.Pipe.Type as Pipe
300304import qualified Streamly.Internal.Data.Stream.StreamD.Type as StreamD
301305
@@ -320,6 +324,7 @@ import Streamly.Internal.Data.Fold.Type
320324-- >>> import qualified Streamly.Internal.Data.Parser as Parser
321325-- >>> import Streamly.Internal.Data.Stream.Serial (SerialT(..))
322326-- >>> import Data.IORef (newIORef, readIORef, writeIORef)
327+-- >>> import qualified Streamly.Internal.Data.Array.Foreign.Mut.Type as MA
323328
324329------------------------------------------------------------------------------
325330-- hoist
@@ -2121,3 +2126,57 @@ unfoldMany (Unfold ustep inject) (Fold fstep initial extract) =
21212126
21222127 {-# INLINE_LATE consume #-}
21232128 consume s a = inject a >>= produce s
2129+
2130+{-# INLINE topBy #-}
2131+topBy :: (MonadIO m, Storable a) =>
2132+ (a -> a -> Ordering)
2133+ -> Int
2134+ -> Fold m a (MA.Array a)
2135+topBy cmp n = Fold step initial extract
2136+
2137+ where
2138+
2139+ initial = do
2140+ arr <- MA.newArray n
2141+ if n <= 0
2142+ then return $ Done arr
2143+ else return $ Partial (arr, 0)
2144+
2145+ step (arr, i) x =
2146+ if i < n
2147+ then do
2148+ arr' <- MA.snoc arr x
2149+ MA.bubble cmp arr'
2150+ return $ Partial (arr', i + 1)
2151+ else do
2152+ x1 <- MA.getIndexUnsafe (i - 1) arr
2153+ case x `cmp` x1 of
2154+ LT -> do
2155+ MA.putIndexUnsafe (i - 1) x arr
2156+ MA.bubble cmp arr
2157+ return $ Partial (arr, i)
2158+ _ -> return $ Partial (arr, i)
2159+
2160+ extract = return . fst
2161+
2162+-- | Fold the input stream to top n elements.
2163+--
2164+-- >>> stream = Stream.fromList [2::Int,7,9,3,1,5,6,11,17]
2165+-- >>> Stream.fold (Fold.top 3) stream >>= MA.toList
2166+-- [17,11,9]
2167+--
2168+-- /Pre-release/
2169+{-# INLINE top #-}
2170+top :: (MonadIO m, Storable a, Ord a) => Int -> Fold m a (MA.Array a)
2171+top = topBy $ flip compare
2172+
2173+-- | Fold the input stream to bottom n elements.
2174+--
2175+-- >>> stream = Stream.fromList [2::Int,7,9,3,1,5,6,11,17]
2176+-- >>> Stream.fold (Fold.bottom 3) stream >>= MA.toList
2177+-- [1,2,3]
2178+--
2179+-- /Pre-release/
2180+{-# INLINE bottom #-}
2181+bottom :: (MonadIO m, Storable a, Ord a) => Int -> Fold m a (MA.Array a)
2182+bottom = topBy compare