reflex-0.9.4.1: src/Data/FastMutableIntMap.hs
{-# 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
, toList
) 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 Data.Patch.Class
import Data.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 'Data.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
toList :: FastMutableIntMap a -> IO [(Int, a)]
toList (FastMutableIntMap r) = IntMap.toList <$> readIORef r