{-# LANGUAGE TypeFamilies #-} -- | -- Module: -- Data.FastMutableIntMap -- Description: -- A mutable version of 'IntMap' module Data.FastMutableIntMap ( FastMutableIntMap , new , newEmpty , insert , isEmpty , getFrozenAndClear , size , applyPatch , PatchIntMap (..) , traverseIntMapPatchWithKey , lookup , forIntersectionWithImmutable_ , for_ , patchIntMapNewElements , patchIntMapNewElementsMap , getDeletions ) where --TODO: Pure JS version --TODO: Fast copy to FastIntMap --TODO: Fast patch type import Prelude hiding (lookup) import Control.Monad.IO.Class import Data.Foldable (traverse_) import Data.IntMap.Strict (IntMap) import qualified Data.IntMap.Strict as IntMap import Data.IORef import Reflex.Patch.Class import Reflex.Patch.IntMap -- | A 'FastMutableIntMap' holds a map of values of type @a@ and allows low-overhead modifications via IO. -- Operations on 'FastMutableIntMap' run in IO. newtype FastMutableIntMap a = FastMutableIntMap (IORef (IntMap a)) -- | Create a new 'FastMutableIntMap' out of an 'IntMap' new :: IntMap a -> IO (FastMutableIntMap a) new m = FastMutableIntMap <$> newIORef m -- | Create a new empty 'FastMutableIntMap' newEmpty :: IO (FastMutableIntMap a) newEmpty = FastMutableIntMap <$> newIORef IntMap.empty -- | Insert an element into a 'FastMutableIntMap' at the given key insert :: FastMutableIntMap a -> Int -> a -> IO () insert (FastMutableIntMap r) k v = modifyIORef' r $ IntMap.insert k v -- | Attempt to lookup an element by key in a 'FastMutableIntMap' lookup :: FastMutableIntMap a -> Int -> IO (Maybe a) lookup (FastMutableIntMap r) k = IntMap.lookup k <$> readIORef r -- | Runs the provided action over the intersection of a 'FastMutableIntMap' and an 'IntMap' forIntersectionWithImmutable_ :: MonadIO m => FastMutableIntMap a -> IntMap b -> (a -> b -> m ()) -> m () forIntersectionWithImmutable_ (FastMutableIntMap r) b f = do a <- liftIO $ readIORef r traverse_ (uncurry f) $ IntMap.intersectionWith (,) a b -- | Runs the provided action over the values of a 'FastMutableIntMap' for_ :: MonadIO m => FastMutableIntMap a -> (a -> m ()) -> m () for_ (FastMutableIntMap r) f = do a <- liftIO $ readIORef r traverse_ f a -- | Checks whether a 'FastMutableIntMap' is empty isEmpty :: FastMutableIntMap a -> IO Bool isEmpty (FastMutableIntMap r) = IntMap.null <$> readIORef r -- | Retrieves the size of a 'FastMutableIntMap' size :: FastMutableIntMap a -> IO Int size (FastMutableIntMap r) = IntMap.size <$> readIORef r -- | Make an immutable snapshot of the datastructure and clear it getFrozenAndClear :: FastMutableIntMap a -> IO (IntMap a) getFrozenAndClear (FastMutableIntMap r) = do result <- readIORef r writeIORef r IntMap.empty return result -- | Updates the value of a 'FastMutableIntMap' with the given patch (see 'Reflex.Patch.IntMap'), -- and returns an 'IntMap' with the modified keys and values. applyPatch :: FastMutableIntMap a -> PatchIntMap a -> IO (IntMap a) applyPatch (FastMutableIntMap r) p@(PatchIntMap m) = do v <- readIORef r writeIORef r $! applyAlways p v return $ IntMap.intersection v m