packages feed

ac-library-hs-1.5.2.0: src/AtCoder/Extra/Vector/Prim.hs

-- | Monadic vector functions with @PrimMonad m@ constraints. They can fuse well.
--
-- Related issue: https://www.github.com/haskell/vector/issues/416.
--
-- Note that these functions are not 100% guaranteed to be sound.
--
-- @since 1.5.2.0
module AtCoder.Extra.Vector.Prim
  ( -- * Construction

    -- ** Monadic initialization
    replicateM,
    generateM,
    iterateNM,

    -- ** Unfolding
    constructNM,
    constructrNM,

    -- * Elementwise operations

    -- ** Monadic mapping
    mapM,
    mapM_,
    imapM,
    imapM_,
    forM,
    forM_,
    iforM,
    iforM_,

    -- ** Monadic zipping
    zipWithM,
    zipWithM_,
    izipWithM,
    izipWithM_,

    -- * Concat map
    concatMapM,
    iconcatMapM,

    -- * Working with predicates

    -- ** Filtering
    filterM,
    mapMaybeM,
    imapMaybeM,

    -- ** Monadic scanl
    prescanlM,
    prescanlM',
    postscanlM,
    postscanlM',
    scanlM,
    scanlM',
    scanl1M,
    scanl1M',
  )
where

import Control.Monad.Primitive (PrimMonad)
import Data.Vector.Fusion.Bundle qualified as Bundle
import Data.Vector.Fusion.Bundle.Monadic qualified as BundleM
import Data.Vector.Generic qualified as VG
import Data.Vector.Generic.Mutable qualified as VGM
import GHC.Stack (HasCallStack)
import Prelude hiding (mapM, mapM_)

-- | ==== Constraints
-- - \(n \ge 0\)
--
-- @since 1.5.2.0
{-# INLINE replicateM #-}
replicateM :: (PrimMonad m, VG.Vector v a) => Int -> m a -> m (v a)
replicateM n f = unstreamPrimM (BundleM.replicateM n f)

-- | ==== Constraints
-- - \(n \ge 0\)
--
-- @since 1.5.2.0
{-# INLINE generateM #-}
generateM :: (PrimMonad m, VG.Vector v a) => Int -> (Int -> m a) -> m (v a)
generateM n f = unstreamPrimM (BundleM.generateM n f)

-- | ==== Constraints
-- - \(n \ge 0\)
--
-- @since 1.5.2.0
{-# INLINE iterateNM #-}
iterateNM :: (PrimMonad m, VG.Vector v a) => Int -> (a -> m a) -> a -> m (v a)
iterateNM n f x = unstreamPrimM (BundleM.iterateNM n f x)

-- | ==== Constraints
-- - \(n \ge 0\)
--
-- @since 1.5.2.0
{-# INLINE constructNM #-}
constructNM :: forall m v a. (PrimMonad m, VG.Vector v a) => Int -> (v a -> m a) -> m (v a)
constructNM n f = do
  v <- VGM.new n
  v' <- VG.unsafeFreeze v
  fill v' 0
  where
    fill :: v a ->Int -> m (v a)
    fill !v i
      | i < n = do
          x <- f (VG.unsafeTake i v)
          VG.elemseq v x $ do
            v' <- VG.unsafeThaw v
            VGM.unsafeWrite v' i x
            v'' <- VG.unsafeFreeze v'
            fill v'' (i + 1)
    fill v _ = pure v

-- | ==== Constraints
-- - \(n \ge 0\)
--
-- @since 1.5.2.0
{-# INLINE constructrNM #-}
constructrNM :: forall m v a. (PrimMonad m, VG.Vector v a) => Int -> (v a -> m a) -> m (v a)
constructrNM n f = do
  v <- n `seq` VGM.new n
  v' <- VG.unsafeFreeze v
  fill v' 0
  where
    fill :: v a ->Int -> m (v a)
    fill !v i
      | i < n = do
          x <- f (VG.unsafeSlice (n - i) i v)
          VG.elemseq v x $ do
            v' <- VG.unsafeThaw v
            VGM.unsafeWrite v' (n - i - 1) x
            v'' <- VG.unsafeFreeze v'
            fill v'' (i + 1)
    fill v _ = pure v

-- | @since 1.5.2.0
{-# INLINE mapM #-}
mapM :: (PrimMonad m, VG.Vector v a, VG.Vector v b) => (a -> m b) -> v a -> m (v b)
mapM f = unstreamPrimM . Bundle.mapM f . VG.stream

-- | @since 1.5.2.0
{-# INLINE imapM #-}
imapM :: (PrimMonad m, VG.Vector v a, VG.Vector v b) => (Int -> a -> m b) -> v a -> m (v b)
imapM f = unstreamPrimM . Bundle.mapM (uncurry f) . Bundle.indexed . VG.stream

-- | @since 1.5.2.0
{-# INLINE mapM_ #-}
mapM_ :: (PrimMonad m, VG.Vector v a) => (a -> m b) -> v a -> m ()
mapM_ f = Bundle.mapM_ f . VG.stream

-- | @since 1.5.2.0
{-# INLINE imapM_ #-}
imapM_ :: (PrimMonad m, VG.Vector v a) => (Int -> a -> m b) -> v a -> m ()
imapM_ f = Bundle.mapM_ (uncurry f) . Bundle.indexed . VG.stream

-- | @since 1.5.2.0
{-# INLINE forM #-}
forM :: (PrimMonad m, VG.Vector v a, VG.Vector v b) => v a -> (a -> m b) -> m (v b)
forM as f = mapM f as

-- | @since 1.5.2.0
{-# INLINE forM_ #-}
forM_ :: (PrimMonad m, VG.Vector v a) => v a -> (a -> m b) -> m ()
forM_ as f = mapM_ f as

-- | @since 1.5.2.0
iforM :: (PrimMonad m, VG.Vector v a, VG.Vector v b) => v a -> (Int -> a -> m b) -> m (v b)
{-# INLINE iforM #-}
iforM as f = imapM f as

-- | @since 1.5.2.0
{-# INLINE iforM_ #-}
iforM_ :: (PrimMonad m, VG.Vector v a) => v a -> (Int -> a -> m b) -> m ()
iforM_ as f = imapM_ f as

-- | @since 1.5.2.0
{-# INLINE zipWithM #-}
zipWithM :: (PrimMonad m, VG.Vector v a, VG.Vector v b, VG.Vector v c) => (a -> b -> m c) -> v a -> v b -> m (v c)
zipWithM f = \as bs -> unstreamPrimM $ Bundle.zipWithM f (VG.stream as) (VG.stream bs)

-- | @since 1.5.2.0
{-# INLINE izipWithM #-}
izipWithM :: (PrimMonad m, VG.Vector v a, VG.Vector v b, VG.Vector v c) => (Int -> a -> b -> m c) -> v a -> v b -> m (v c)
izipWithM m as bs = unstreamPrimM . Bundle.zipWithM (uncurry m) (Bundle.indexed (VG.stream as)) $ VG.stream bs

-- | @since 1.5.2.0
{-# INLINE zipWithM_ #-}
zipWithM_ :: (PrimMonad m, VG.Vector v a, VG.Vector v b) => (a -> b -> m c) -> v a -> v b -> m ()
zipWithM_ f = \as bs -> Bundle.zipWithM_ f (VG.stream as) (VG.stream bs)

-- | @since 1.5.2.0
{-# INLINE izipWithM_ #-}
izipWithM_ :: (PrimMonad m, VG.Vector v a, VG.Vector v b) => (Int -> a -> b -> m c) -> v a -> v b -> m ()
izipWithM_ m as bs = Bundle.zipWithM_ (uncurry m) (Bundle.indexed (VG.stream as)) $ VG.stream bs

-- | Maps each element to a vector and concatenate the results.
--
-- @since 1.5.2.0
{-# INLINE concatMapM #-}
concatMapM ::
  (HasCallStack, PrimMonad m, VG.Vector v a, VG.Vector v b) =>
  (a -> m (v b)) ->
  v a ->
  m (v b)
concatMapM f =
  unstreamPrimM
    . BundleM.concatVectors
    . BundleM.mapM f
    . BundleM.fromVector

-- | Maps each element to a vector and concatenate the results.
--
-- @since 1.5.2.0
{-# INLINE iconcatMapM #-}
iconcatMapM ::
  (HasCallStack, PrimMonad m, VG.Vector v a, VG.Vector v b) =>
  (Int -> a -> m (v b)) ->
  v a ->
  m (v b)
iconcatMapM f =
  unstreamPrimM
    . BundleM.concatVectors
    . BundleM.mapM (uncurry f)
    . BundleM.indexed
    . BundleM.fromVector

-- | @since 1.5.2.0
{-# INLINE filterM #-}
filterM :: (PrimMonad m, VG.Vector v a) => (a -> m Bool) -> v a -> m (v a)
filterM f = unstreamPrimM . Bundle.filterM f . VG.stream

-- | @since 1.5.2.0
mapMaybeM :: (PrimMonad m, VG.Vector v a, VG.Vector v b) => (a -> m (Maybe b)) -> v a -> m (v b)
{-# INLINE mapMaybeM #-}
mapMaybeM f = unstreamPrimM . Bundle.mapMaybeM f . VG.stream

-- | @since 0.12.2.0
{-# INLINE imapMaybeM #-}
imapMaybeM :: (PrimMonad m, VG.Vector v a, VG.Vector v b) => (Int -> a -> m (Maybe b)) -> v a -> m (v b)
imapMaybeM f = unstreamPrimM . Bundle.mapMaybeM (\(i, a) -> f i a) . Bundle.indexed . VG.stream

-- | https://github.com/haskell/vector/issues/416
{-# INLINE [1] unstreamPrimM #-}
unstreamPrimM :: (PrimMonad m, VG.Vector v a) => BundleM.Bundle m u a -> m (v a)
unstreamPrimM s = VGM.munstream s >>= VG.unsafeFreeze

-- | @since 1.5.2.0
{-# INLINE prescanlM #-}
prescanlM :: (HasCallStack, PrimMonad m, VG.Vector v a, VG.Vector v b) => (a -> b -> m a) -> a -> v b -> m (v a)
prescanlM f x0 =
  unstreamPrimM
    . prescanlMB f x0
    . VG.stream

-- | @since 1.5.2.0
{-# INLINE prescanlM' #-}
prescanlM' :: (HasCallStack, PrimMonad m, VG.Vector v a, VG.Vector v b) => (a -> b -> m a) -> a -> v b -> m (v a)
prescanlM' f x0 =
  unstreamPrimM
    . prescanlMB' f x0
    . VG.stream

-- | @since 1.5.2.0
{-# INLINE postscanlM #-}
postscanlM :: (HasCallStack, PrimMonad m, VG.Vector v a, VG.Vector v b) => (a -> b -> m a) -> a -> v b -> m (v a)
postscanlM f x0 =
  unstreamPrimM
    . postscanlMB f x0
    . VG.stream

-- | @since 1.5.2.0
{-# INLINE postscanlM' #-}
postscanlM' :: (HasCallStack, PrimMonad m, VG.Vector v a, VG.Vector v b) => (a -> b -> m a) -> a -> v b -> m (v a)
postscanlM' f x0 =
  unstreamPrimM
    . postscanlMB' f x0
    . VG.stream

-- | @since 1.5.2.0
{-# INLINE scanlM #-}
scanlM :: (HasCallStack, PrimMonad m, VG.Vector v a, VG.Vector v b) => (a -> b -> m a) -> a -> v b -> m (v a)
scanlM f x0 =
  unstreamPrimM
    . scanlMB f x0
    . VG.stream

-- | @since 1.5.2.0
{-# INLINE scanlM' #-}
scanlM' :: (HasCallStack, PrimMonad m, VG.Vector v a, VG.Vector v b) => (a -> b -> m a) -> a -> v b -> m (v a)
scanlM' f x0 =
  unstreamPrimM
    . scanlMB' f x0
    . VG.stream

-- | @since 1.5.2.0
{-# INLINE scanl1M #-}
scanl1M :: (HasCallStack, PrimMonad m, VG.Vector v a) => (a -> a -> m a) -> v a -> m (v a)
scanl1M f =
  unstreamPrimM
    . scanl1MB f
    . VG.stream

-- | @since 1.5.2.0
{-# INLINE scanl1M' #-}
scanl1M' :: (HasCallStack, PrimMonad m, VG.Vector v a) => (a -> a -> m a) -> v a -> m (v a)
scanl1M' f =
  unstreamPrimM
    . scanl1MB' f
    . VG.stream

{-# INLINE prescanlMB #-}
prescanlMB :: (Monad m) => (a -> b -> m a) -> a -> Bundle.Bundle v b -> BundleM.Bundle m v a
prescanlMB f x0 = BundleM.prescanlM f x0 . Bundle.lift

{-# INLINE prescanlMB' #-}
prescanlMB' :: (Monad m) => (a -> b -> m a) -> a -> Bundle.Bundle v b -> BundleM.Bundle m v a
prescanlMB' f x0 = BundleM.prescanlM' f x0 . Bundle.lift

{-# INLINE postscanlMB #-}
postscanlMB :: (Monad m) => (a -> b -> m a) -> a -> Bundle.Bundle v b -> BundleM.Bundle m v a
postscanlMB f x0 = BundleM.postscanlM f x0 . Bundle.lift

{-# INLINE postscanlMB' #-}
postscanlMB' :: (Monad m) => (a -> b -> m a) -> a -> Bundle.Bundle v b -> BundleM.Bundle m v a
postscanlMB' f x0 = BundleM.postscanlM' f x0 . Bundle.lift

{-# INLINE scanlMB #-}
scanlMB :: (Monad m) => (a -> b -> m a) -> a -> Bundle.Bundle v b -> BundleM.Bundle m v a
scanlMB f x0 = BundleM.scanlM f x0 . Bundle.lift

{-# INLINE scanlMB' #-}
scanlMB' :: (Monad m) => (a -> b -> m a) -> a -> Bundle.Bundle v b -> BundleM.Bundle m v a
scanlMB' f x0 = BundleM.scanlM' f x0 . Bundle.lift

{-# INLINE scanl1MB #-}
scanl1MB :: (Monad m) => (a -> a -> m a) -> Bundle.Bundle v a -> BundleM.Bundle m v a
scanl1MB f = BundleM.scanl1M f . Bundle.lift

{-# INLINE scanl1MB' #-}
scanl1MB' :: (Monad m) => (a -> a -> m a) -> Bundle.Bundle v a -> BundleM.Bundle m v a
scanl1MB' f = BundleM.scanl1M' f . Bundle.lift