{-# 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