ac-library-hs-1.2.2.1: src/AtCoder/Extra/Seq/Map.hs
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
-- | Key-value pairs with monoid products and monoid actions on them through the `SegAct` instance.
--
-- ==== Performance
-- This module is __extremely slow__ as an ordinary map. Do not use it unless you need monoid
-- products.
--
-- ==== __Example__
--
-- >>> import AtCoder.Extra.Monoid.RangeAdd qualified as RangeAdd
-- >>> import AtCoder.Extra.Seq.Map qualified as M
-- >>> import Data.Semigroup (Sum (..))
-- >>> import Data.Vector.Unboxed qualified as VU
-- >>> m <- M.new @_ @(RangeAdd.RangeAdd (Sum Int)) @Int @(Sum Int) 10
-- >>> M.insert m 1 10
-- >>> M.insert m 3 30
-- >>> M.prod m 1 2
-- Sum {getSum = 10}
--
-- @since 1.2.1.0
module AtCoder.Extra.Seq.Map
( -- * Map
Map (..),
-- * Re-exports
SegAct (..),
-- * Constructors
new,
build,
reset,
-- * Metadata
capacity,
size,
-- * Key-based operations
-- ** Read/write
member,
lookup,
adjust,
-- ** Insert/delete
insert,
insertWith,
delete,
delete_,
-- ** Products
-- sliceST,
prod,
prodMaybe,
allProd, -- FIXME: rename to `prodAll`
-- ** Applications
applyIn,
applyAll,
-- ** Bisection methods
lookupLE,
lookupLT,
lookupGE,
lookupGT,
-- * Index-based operations
-- ** Read/write
readAt,
readMaybeAt,
writeAt,
modifyAt,
exchangeAt,
-- ** Products
prodInInterval,
-- TODO: prodIn
-- ** Applications
applyInInterval,
-- ** Bisection methods
ilowerBound,
ilowerBoundM,
ilowerBoundProd,
ilowerBoundProdM,
-- * Conversion
freeze,
)
where
import AtCoder.Extra.Pool qualified as P
import AtCoder.Extra.Seq qualified as Seq
import AtCoder.Extra.Seq.Raw qualified as Raw
import AtCoder.Internal.Assert qualified as ACIA
import AtCoder.LazySegTree (SegAct (..))
import Control.Monad (unless, when)
import Control.Monad.Primitive (PrimMonad, PrimState, stToPrim)
import Control.Monad.ST (ST)
import Data.Coerce (coerce)
import Data.Ord (comparing)
import Data.Vector.Algorithms.Intro qualified as VAI
import Data.Vector.Generic.Mutable qualified as VGM
import Data.Vector.Unboxed qualified as VU
import Data.Vector.Unboxed.Mutable qualified as VUM
import GHC.Stack (HasCallStack)
import Prelude hiding (lookup, read, reverse, seq)
-- | Key-value pairs with monoid products and monoid actions on them through the `SegAct` instance.
--
-- @since 1.2.1.0
data Map s f k v = Map
{ -- | The sequence storage
--
-- @since 1.2.1.0
seqMap :: !(Seq.Seq s f v),
-- | Keys
--
-- @since 1.2.1.0
kMap :: !(VUM.MVector s k),
-- | Handle of the root node.
--
-- @since 1.2.1.0
rootMap :: !(Seq.Handle s)
}
{-# INLINE assertRootST #-}
assertRootST :: (HasCallStack) => Raw.Seq s f v -> P.Index -> ST s ()
assertRootST Seq.Seq {pSeq} i = do
p <- VGM.read pSeq (coerce i)
let !_ = ACIA.runtimeAssert (P.nullIndex p) $ "AtCoder.Extra.Seq.Map.assertRootST: not a root (node `" ++ show i ++ "`, parent `" ++ show p ++ "`)"
pure ()
-- | \(O(n)\) Creates a new `Map` of capacity \(n\). Always prefer `build` to `new` for performance.
--
-- @since 1.2.1.0
{-# INLINEABLE new #-}
new :: (PrimMonad m, Monoid f, VU.Unbox f, VU.Unbox k, VU.Unbox v, Monoid v) => Int -> m (Map (PrimState m) f k v)
new n = stToPrim $ do
seqMap <- Seq.new n
kMap <- VUM.unsafeNew n
rootMap <- Seq.newHandle P.undefIndex
pure Map {..}
-- | \(O(n \log n)\) Creates a new `Map` of capacity \(n\) with initial values. Always prefer `build` to
-- `new` for performance.
--
-- @since 1.2.1.0
{-# INLINEABLE build #-}
build :: (HasCallStack, PrimMonad m, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, VU.Unbox v, Monoid v) => Int -> VU.Vector (k, v) -> m (Map (PrimState m) f k v)
build n kvs = stToPrim $ do
-- let !_ = ACIA.runtimeAssert (VU.length kvs <= n) "AtCoder.Extra.Seq.Map"
seqMap <- Seq.new n
kMap <- VUM.unsafeNew n
-- note that `unzip` is O(1) for tuples:
let (!ks, !vs) = VU.unzip $ VU.modify (VAI.sortBy (comparing fst)) kvs
VU.iforM_ ks $ VGM.write kMap
rootMap <- Seq.newSeq seqMap vs
pure Map {..}
-- | \(O(1)\) Clears the map. All the handles must not be used again.
--
-- @since 1.2.1.0
{-# INLINEABLE reset #-}
reset :: (PrimMonad m, Monoid f, VU.Unbox f, VU.Unbox k, VU.Unbox v, Monoid v) => Map (PrimState m) f k v -> m ()
reset Map {..} = stToPrim $ do
Raw.resetST seqMap
VGM.write (Seq.unHandle rootMap) 0 P.undefIndex
-- -------------------------------------------------------------------------------------------
-- Metadta
-- -------------------------------------------------------------------------------------------
-- | \(O(1)\) Returns the maximum number of elements the map can store.
--
-- @since 1.2.1.0
{-# INLINEABLE capacity #-}
capacity :: Map s f k v -> Int
capacity Map {seqMap} = Raw.capacity seqMap
-- | \(O(1)\) Returns the number of elements in the map.
--
-- @since 1.2.1.0
{-# INLINEABLE size #-}
size :: (PrimMonad m) => Map (PrimState m) f k v -> m Int
size Map {..} = stToPrim $ do
root <- VGM.read (Seq.unHandle rootMap) 0
Raw.lengthST seqMap root
-- -------------------------------------------------------------------------------------------
-- Key-based operations
-- -------------------------------------------------------------------------------------------
-- | Amortized \(O(\log n)\). Finds a node with key \(k\).
{-# INLINEABLE lookupNodeST #-}
lookupNodeST :: (HasCallStack, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map s f k v -> k -> ST s (Bool, P.Index, P.Index)
lookupNodeST Map {..} k = do
root <- VGM.read (Seq.unHandle rootMap) 0
if P.nullIndex root
then pure (False, P.undefIndex, P.undefIndex)
else do
(!l, !root') <- Raw.maxRightWithST seqMap root $ \i -> do
ki <- VGM.read kMap (coerce i)
pure $ ki <= k
VGM.write (Seq.unHandle rootMap) 0 root'
if P.nullIndex l
then do
pure (False, root', root')
else do
kl <- VGM.read kMap (coerce l)
pure (kl == k, l, root')
-- | Amoritzed \(O(\log n)\). Returns whether a node with key \(k\) is in the map.
--
-- @since 1.2.1.0
{-# INLINE member #-}
member :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> m Bool
member m k = stToPrim $ do
(!b, !_, !_) <- lookupNodeST m k
pure b
-- | Amortized \(O(\log n)\). Looks up for the monoid value of a node with key \(k\).
--
-- @since 1.2.1.0
{-# INLINE lookup #-}
lookup :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> m (Maybe v)
lookup m@Map {..} k = stToPrim $ do
(!b, !l, !_) <- lookupNodeST m k
if b
then do
Raw.splayST seqMap l True
Just <$> VGM.read (Seq.vSeq seqMap) 0
else do
pure Nothing
-- | Amoritzed \(O(\log n)\). Adjusts the monoid value of a node with key \(k\).
--
-- @since 1.2.1.0
{-# INLINE adjust #-}
adjust :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> (v -> v) -> k -> m ()
adjust m@Map {..} f k = stToPrim $ do
(!b, !l, !_) <- lookupNodeST m k
when b $ do
Raw.splayST seqMap l True
VGM.write (Seq.unHandle rootMap) 0 l
Raw.modifyNodeST seqMap f l
-- | Amortized \(O(\log n)\). Inserts a \((k, v)\) pair. If the key is already present in the map,
-- the associated value is replaced with the supplied value.
--
-- @since 1.2.1.0
{-# INLINE insert #-}
insert :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> v -> m ()
insert m k v = stToPrim $ do
insertWithST m const k v
-- | Amortized \(O(\log n)\). Inserts a \((k, v)\) pairs, combining new value and old value.
--
-- @since 1.2.1.0
{-# INLINE insertWith #-}
insertWith ::
(HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) =>
-- | Map
Map (PrimState m) f k v ->
-- | new -> old -> combined
(v -> v -> v) ->
-- | Key
k ->
-- | Value
v ->
m ()
insertWith m f k v = stToPrim $ do
insertWithST m f k v
-- | Amortized \(O(\log n)\).
{-# INLINEABLE insertWithST #-}
insertWithST ::
(HasCallStack, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) =>
-- | Map
Map s f k v ->
-- | new -> old -> combined
(v -> v -> v) ->
-- | Key
k ->
-- | Value
v ->
ST s ()
insertWithST Map {..} f k v = stToPrim $ do
-- split and merge
VGM.unsafeModifyM
(Seq.unHandle rootMap)
( \root -> do
(!l, !r) <- Raw.splitMaxRightWithST seqMap root $ \i -> do
ki <- VGM.read kMap (coerce i)
pure $ ki <= k
if P.nullIndex l
then do
-- insert
node <- Raw.newNodeST seqMap v
VGM.write kMap (coerce node) k
Raw.mergeST seqMap node r
else do
kl <- VGM.read kMap (coerce l)
if kl == k
then do
-- overwrite the node
Raw.splayST seqMap l True
Raw.modifyNodeST seqMap (f v) l
VGM.write kMap (coerce l) k
Raw.mergeST seqMap l r
else do
-- insert
node <- Raw.newNodeST seqMap v
VGM.write kMap (coerce node) k
Raw.merge3ST seqMap l node r
)
0
-- | Amortized \(O(\log n)\). Deletes an element with key \(k\).
--
-- @since 1.2.1.0
{-# INLINEABLE delete #-}
delete :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> m (Maybe v)
delete m@Map {..} k = stToPrim $ do
(!b, !l, !_) <- lookupNodeST m k
if b
then do
let Raw.Seq {..} = seqMap
Raw.splayST seqMap l True
xl <- VGM.read lSeq $ coerce l
xr <- VGM.read rSeq $ coerce l
unless (P.nullIndex xl) $ VGM.write pSeq (coerce xl) P.undefIndex
unless (P.nullIndex xr) $ VGM.write pSeq (coerce xr) P.undefIndex
v <- VGM.read vSeq $ coerce l
Raw.freeNodeST seqMap l
root'' <- Raw.mergeST seqMap xl xr
VGM.write (Seq.unHandle rootMap) 0 root''
pure $ Just v
else do
pure Nothing
-- | Amortized \(O(\log n)\). Deletes an element with key \(k\).
--
-- @since 1.2.1.0
{-# INLINE delete_ #-}
delete_ :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> m ()
delete_ m k = stToPrim $ do
_ <- delete m k
pure ()
-- | Amortized \(O(\log n)\). Captures a node that corresponds to \([k1, k2)\).
{-# INLINEABLE sliceST #-}
sliceST :: (HasCallStack, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map s f k v -> k -> k -> ST s P.Index
sliceST Map {..} k1 k2 = do
let handle = Seq.unHandle rootMap
root <- VGM.read handle 0
if P.nullIndex root
then pure P.undefIndex
else do
(!lm, !r) <- Raw.splitMaxRightWithST seqMap root $ \i -> do
k' <- VGM.read kMap (coerce i)
pure $! k' < k2
case (P.nullIndex lm, P.nullIndex r) of
(True, True) -> error "unreachable"
(True, False) -> do
VGM.write handle 0 r
pure P.undefIndex
(False, True) -> do
(!l, !root') <- Raw.maxRightWithST seqMap lm $ \i -> do
k' <- VGM.read kMap (coerce i)
pure $! k' < k1
if P.nullIndex l
then do
VGM.write handle 0 root'
pure root'
else do
Raw.splayST seqMap l True
VGM.write handle 0 l
VGM.read rSeq (coerce l)
(False, False) -> do
r' <- Raw.splayKthST seqMap r 0
VGM.write handle 0 r'
(!l, !root') <- Raw.maxRightWithST seqMap lm $ \i -> do
k' <- VGM.read kMap (coerce i)
pure $! k' < k1
if P.nullIndex l
then do
-- root' is [l, r)
VGM.write pSeq (coerce root') r'
VGM.write lSeq (coerce r') root'
Raw.updateNodeST seqMap root'
pure root'
else do
-- o--l--o--r--o
-- r
-- /---/
-- l
-- \
-- m
Raw.splayST seqMap l True
VGM.write pSeq (coerce l) r'
VGM.write lSeq (coerce r') l
Raw.updateNodeST seqMap r'
VGM.read rSeq (coerce l)
where
Raw.Seq {..} = seqMap
-- | Amortized \(O(\log n)\). Returns the monoid product in an interval \([k_1, k_2)\). Throws an
-- error for \(k_1 \gt k_2\).
--
-- ==== Constraints
-- - \(k_1 \le k_2\)
--
-- @since 1.2.1.0
{-# INLINE prod #-}
prod :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> k -> m v
prod m@Map {..} l r = stToPrim $ do
let !_ = ACIA.runtimeAssert (l <= r) "AtCoder.Extra.Seq.Map.prod: k1 > k2"
root <- VGM.read (Seq.unHandle rootMap) 0
if P.nullIndex root || l == r
then pure mempty
else unsafeProdST m l r
-- | Amortized \(O(\log n)\). Returns the monoid product in an interval \([k_1, k_2)\). Returns
-- `Nothing` if an invalid interval is given or for an empty sequence.
--
-- @since 1.2.1.0
{-# INLINE prodMaybe #-}
prodMaybe :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> k -> m (Maybe v)
prodMaybe m l r
| l > r = pure Nothing
| otherwise = Just <$> prod m l r
-- | Amortized \(O(\log n)\). Returns the monoid product in an interval \([k_1, k_2)\). Returns
-- `Nothing` if an invalid interval is given or for an empty sequence.
--
-- @since 1.2.1.0
{-# INLINE allProd #-}
allProd :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> m v
allProd Map {..} = do
root <- VGM.read (Seq.unHandle rootMap) 0
if P.nullIndex root
then pure mempty
else VGM.read (Raw.prodSeq seqMap) (coerce root)
-- | Amortized \(O(\log n)\).
--
-- ==== Constraint
-- - \(0 \le \lt r \le n\). Note that the interval must have positive length.
{-# INLINEABLE unsafeProdST #-}
unsafeProdST :: (HasCallStack, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map s f k v -> k -> k -> ST s v
unsafeProdST m@Map {..} l r = do
let Seq.Seq {..} = seqMap
root <- VGM.read (Seq.unHandle rootMap) 0
assertRootST seqMap root -- TODO: remove
target <- sliceST m l r
if P.nullIndex target
then pure mempty
else do
res <- VGM.read prodSeq $ coerce target
Raw.splayST seqMap target True
VGM.write (Seq.unHandle rootMap) 0 target
pure res
-- | Amortized \(O(\log n)\). Given an interval \([l, r)\), applies a monoid action \(f\).
--
-- ==== Constraints
-- - \(0 \le l \le r \le n\)
-- - The root must point to a non-empty sequence.
--
-- @since 1.2.1.0
{-# INLINEABLE applyIn #-}
applyIn :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> k -> f -> m ()
applyIn m@Map {..} l r act = stToPrim $ do
let !_ = ACIA.runtimeAssert (l <= r) "AtCoder.Extra.Seq.Map.applyIn: k1 > k2"
unless (l == r) $ do
target <- sliceST m l r
unless (P.nullIndex target) $ do
Raw.applyNodeST seqMap target act
Raw.splayST seqMap target True
VGM.write (Seq.unHandle rootMap) 0 target
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE applyAll #-}
applyAll :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> f -> m ()
applyAll Map {..} act = stToPrim $ do
root <- VGM.read (Seq.unHandle rootMap) 0
Raw.applyToRootST seqMap root act
-- -------------------------------------------------------------------------------------------
-- Key-based bisection method
-- -------------------------------------------------------------------------------------------
-- | Amortized \(O(\log n)\). Looks up for \((k, v)\) pair with the maximum key \(k\) such that
-- \(k \le k_{\mathrm{ref}}\).
--
-- @since 1.2.1.0
{-# INLINE lookupLE #-}
lookupLE :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> m (Maybe (k, v))
lookupLE m k = stToPrim $ do
lookupImplL m k EQ
-- | Amortized \(O(\log n)\). Looks up for \((k, v)\) pair with the maximum key \(k\) such that
-- \(k \lt k_{\mathrm{ref}}\).
--
-- @since 1.2.1.0
{-# INLINE lookupLT #-}
lookupLT :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> m (Maybe (k, v))
lookupLT m k = stToPrim $ do
lookupImplL m k LT
-- | Amortized \(O(\log n)\).
{-# INLINEABLE lookupImplL #-}
lookupImplL :: (HasCallStack, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map s f k v -> k -> Ordering -> ST s (Maybe (k, v))
lookupImplL Map {..} k o = do
root <- VGM.read (Seq.unHandle rootMap) 0
if P.nullIndex root
then pure Nothing
else do
(!l, !root') <- Raw.maxRightWithST seqMap root $ \i -> do
ki <- VGM.read kMap (coerce i)
pure $! compare ki k <= o
if P.nullIndex l
then do
VGM.write (Seq.unHandle rootMap) 0 root'
pure Nothing
else do
Raw.splayST seqMap l True -- TODO: is it True?
VGM.write (Seq.unHandle rootMap) 0 l
kl <- VGM.read kMap (coerce l)
vl <- VGM.read (Seq.vSeq seqMap) (coerce l)
pure $! Just (kl, vl)
-- | Amortized \(O(\log n)\). Looks up for \((k, v)\) pair with the minimum key \(k\) such that
-- \(k \ge k_{\mathrm{ref}}\).
--
-- @since 1.2.1.0
{-# INLINE lookupGE #-}
lookupGE :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> m (Maybe (k, v))
lookupGE m k = stToPrim $ do
lookupImplR m k LT
-- | Amortized \(O(\log n)\). Looks up for \((k, v)\) pair with the minimum key \(k\) such that
-- \(k \gt k_{\mathrm{ref}}\).
--
-- @since 1.2.1.0
{-# INLINE lookupGT #-}
lookupGT :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> k -> m (Maybe (k, v))
lookupGT m k = stToPrim $ do
lookupImplR m k EQ
-- | Amortized \(O(\log n)\).
{-# INLINEABLE lookupImplR #-}
lookupImplR :: (HasCallStack, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map s f k v -> k -> Ordering -> ST s (Maybe (k, v))
lookupImplR Map {..} k o = do
let handle = Seq.unHandle rootMap
root <- VGM.read handle 0
if P.nullIndex root
then pure Nothing
else do
let Raw.Seq {..} = seqMap
(!l, !root') <- Raw.maxRightWithST seqMap root $ \i -> do
k' <- VGM.read kMap (coerce i)
pure $! compare k' k <= o
if P.nullIndex l
then do
r <- Raw.splayKthST seqMap (coerce root') 0
VGM.write handle 0 r
kr <- VGM.read kMap (coerce r)
vr <- VGM.read vSeq (coerce r)
pure $ Just (kr, vr)
else do
Raw.splayST seqMap l True -- TODO: is it `True`?
r0 <- VGM.read rSeq (coerce l)
if P.nullIndex r0
then do
VGM.write handle 0 l
pure Nothing
else do
r <- Raw.splayKthST seqMap (coerce r0) 0
VGM.write handle 0 r
kr <- VGM.read kMap (coerce r)
vr <- VGM.read vSeq (coerce r)
pure $ Just (kr, vr)
-- -------------------------------------------------------------------------------------------
-- Index-based operations
-- -------------------------------------------------------------------------------------------
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE readAt #-}
readAt :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> Int -> m v
readAt Map {..} i = stToPrim $ do
Seq.read seqMap rootMap i
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE readMaybeAt #-}
readMaybeAt :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> Int -> m (Maybe v)
readMaybeAt Map {..} i = stToPrim $ do
Seq.readMaybe seqMap rootMap i
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE writeAt #-}
writeAt :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> Int -> v -> m ()
writeAt Map {..} i v = stToPrim $ do
Seq.write seqMap rootMap i v
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE modifyAt #-}
modifyAt :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> (v -> v) -> Int -> m ()
modifyAt Map {..} f i = stToPrim $ do
Seq.modify seqMap rootMap f i
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE exchangeAt #-}
exchangeAt :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> Int -> v -> m v
exchangeAt Map {..} i v = stToPrim $ do
Seq.exchange seqMap rootMap i v
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE prodInInterval #-}
prodInInterval :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> Int -> Int -> m v
prodInInterval Map {..} l r = stToPrim $ do
Seq.prod seqMap rootMap l r
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE applyInInterval #-}
applyInInterval :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> Int -> Int -> f -> m ()
applyInInterval Map {..} l r f = stToPrim $ do
Seq.applyIn seqMap rootMap l r f
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE ilowerBound #-}
ilowerBound ::
(HasCallStack, PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) =>
-- | Map
Map (PrimState m) f k a ->
-- | User predicate \(f(i, v_i)\) that takes the index and the monoid value
(Int -> a -> Bool) ->
-- | Maximum \(r\), where \(f(i, v_i)\) holds for \(i \in [0, r)\)
m Int
ilowerBound Map {..} f = stToPrim $ do
Seq.ilowerBound seqMap rootMap f
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE ilowerBoundM #-}
ilowerBoundM ::
(HasCallStack, PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) =>
-- | Map
Map (PrimState m) f k a ->
-- | User predicate \(f(i, v_i)\) that takes the index and the monoid value
(Int -> a -> m Bool) ->
-- | Maximum \(r\), where \(f(i, v_i)\) holds for \(i \in [0, r)\)
m Int
ilowerBoundM Map {..} f = do
Seq.ilowerBoundM seqMap rootMap f
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE ilowerBoundProd #-}
ilowerBoundProd ::
(HasCallStack, PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) =>
-- | Map
Map (PrimState m) f k a ->
-- | User predicate \(f(i, v_0 \dots v_i)\) that takes the index and the monoid product
(Int -> a -> Bool) ->
-- | Maximum \(r\), where \(f(i, v_0 \dots v_i)\) holds for \(i \in [0, r)\)
m Int
ilowerBoundProd Map {..} f = stToPrim $ do
Seq.ilowerBoundProd seqMap rootMap f
-- | Amortized \(O(\log n)\).
--
-- @since 1.2.1.0
{-# INLINE ilowerBoundProdM #-}
ilowerBoundProdM ::
(HasCallStack, PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) =>
-- | Map
Map (PrimState m) f k a ->
-- | User predicate \(f(i, v_0 \dots v_i)\) that takes the index and the monoid product
(Int -> a -> m Bool) ->
-- | Maximum \(r\), where \(f(i, v_0 \dots v_i)\) holds for \(i \in [0, r)\)
m Int
ilowerBoundProdM Map {..} f = do
Seq.ilowerBoundProdM seqMap rootMap f
-- -------------------------------------------------------------------------------------------
-- Conversions
-- -------------------------------------------------------------------------------------------
-- | \(O(n)\) Returns the \(k, v\) pairs in the map
--
-- @since 1.2.1.0
{-# INLINEABLE freeze #-}
freeze :: (HasCallStack, PrimMonad m, Eq f, Monoid f, VU.Unbox f, Ord k, VU.Unbox k, Monoid v, VU.Unbox v, SegAct f v) => Map (PrimState m) f k v -> m (VU.Vector (k, v))
freeze Map {..} = stToPrim $ do
let Raw.Seq {..} = seqMap
root0 <- VGM.read (Seq.unHandle rootMap) 0
if P.nullIndex root0
then pure VU.empty
else do
assertRootST seqMap root0
size_ <- VGM.read sSeq (coerce root0)
res <- VUM.unsafeNew size_
let inner i root
| P.nullIndex root = pure i
| otherwise = do
-- visit from left to right
Raw.propNodeST seqMap root
i' <- inner i =<< VGM.read lSeq (coerce root)
kx <- VGM.read kMap (coerce root)
vx <- VGM.read vSeq (coerce root)
VGM.write res i' (kx, vx)
inner (i' + 1) =<< VGM.read rSeq (coerce root)
_ <- inner 0 root0
VU.unsafeFreeze res