packages feed

timemap 0.0.2 → 0.0.3

raw patch · 3 files changed

+122/−41 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.TimeMap: adjustWithTime :: (Hashable k, Eq k) => UTCTime -> (a -> a) -> k -> TimeMap k a -> STM ()
+ Data.TimeMap: insertWithTime :: (Hashable k, Eq k) => UTCTime -> k -> a -> TimeMap k a -> STM ()
+ Data.TimeMap: toList :: (Hashable k, Eq k) => TimeMap k a -> STM [(k, a)]
+ Data.TimeMap: updateWithTime :: (Hashable k, Eq k) => UTCTime -> (a -> Maybe a) -> k -> TimeMap k a -> STM ()

Files

src/Data/TimeMap.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE+    BangPatterns+  #-}+ {- | Module      : Data.TimeMap Copyright   : (c) 2015 Athan Clark@@ -21,8 +25,11 @@   , -- * Construction     newTimeMap   , insert+  , insertWithTime   , update+  , updateWithTime   , adjust+  , adjustWithTime   , delete   , -- * Query     lookup@@ -30,6 +37,7 @@   , ageOf   , keys   , elems+  , toList   , size   , null   , -- * Filter@@ -42,23 +50,28 @@ import Prelude hiding (lookup, null, filter) import Data.Time (UTCTime, NominalDiffTime, addUTCTime, diffUTCTime, getCurrentTime) import Data.Hashable (Hashable (..))-import Data.Maybe (fromMaybe)-import qualified Data.Map                 as Map+import Data.Maybe (fromMaybe, fromJust)+import qualified Data.Map.Strict          as Map import qualified Data.HashSet             as HS import qualified Data.TimeMap.Internal    as MM import qualified STMContainers.Map        as HT import qualified Focus                    as F import qualified ListT                    as L+import Control.Monad (forM) import Control.Concurrent.STM  --- | A mutable reference for a time-indexed map, similar to a 'Data.STRef.STRef'.-data TimeMap k a = TimeMap-  { timeMap :: TVar (MM.MultiMap UTCTime k)-  , keysMap :: HT.Map k (UTCTime, a)+data TimeIndexed a = TimeIndexed+  { indexedTime  :: {-# UNPACK #-} !UTCTime+  , indexedValue :: a   }  +-- | A mutable reference for a time-indexed map, similar to a 'Data.STRef.STRef'.+data TimeMap k a = TimeMap+  { timeMap :: !(TVar (MM.MultiMap UTCTime k))+  , keysMap :: !(HT.Map k (TimeIndexed a))+  }   -- | Create a fresh, empty map.@@ -73,35 +86,55 @@           ) => k -> a -> TimeMap k a -> IO () insert k x xs = do   now <- getCurrentTime-  atomically $ HT.focus (go now) k (keysMap xs)+  atomically $ insertWithTime now k x xs++{-# INLINEABLE insert #-}++insertWithTime :: ( Hashable k+                  , Eq k+                  ) => UTCTime -> k -> a -> TimeMap k a -> STM ()+insertWithTime now k x xs =+  HT.focus go k (keysMap xs)   where-    go now mx = do+    go mx = do       modifyTVar (timeMap xs) $         let changeOld = case mx of-                          Nothing          -> id-                          Just (oldTime,_) -> MM.remove oldTime k-        in MM.insert now k . changeOld-      pure ((), F.Replace (now, x))+                          Nothing -> id+                          Just (TimeIndexed oldTime _) ->+                            MM.remove oldTime k+        in  MM.insert now k . changeOld+      pure ((), F.Replace (TimeIndexed now x)) +{-# INLINEABLE insertWithTime #-}  -- | Performs a non-mutating lookup for some key. lookup :: ( Hashable k           , Eq k           ) => k -> TimeMap k a -> STM (Maybe a)-lookup k xs = do-  mx <- HT.lookup k (keysMap xs)-  pure (snd <$> mx)+lookup k xs =+  (\mx' -> indexedValue <$> mx') <$> HT.lookup k (keysMap xs) +{-# INLINEABLE lookup #-}  keys :: ( Hashable k         , Eq k         ) => TimeMap k a -> STM (HS.HashSet k) keys xs = MM.elems <$> readTVar (timeMap xs) +{-# INLINEABLE keys #-}  elems :: TimeMap k a -> STM [a]-elems xs = L.toList $ (snd . snd) <$> HT.stream (keysMap xs)+elems xs = L.toList $ (indexedValue . snd) <$> HT.stream (keysMap xs) +toList :: ( Hashable k+          , Eq k+          ) => TimeMap k a -> STM [(k, a)]+toList xs = do+  keys' <- (HS.toList . MM.elems) <$> readTVar (timeMap xs)+  forM keys' $ \k -> do+    mVal <- HT.lookup k (keysMap xs)+    pure (k, indexedValue (fromJust mVal))+ size :: TimeMap k a -> STM Int size xs = length <$> elems xs @@ -113,16 +146,19 @@           ) => k -> TimeMap k a -> STM (Maybe UTCTime) timeOf k xs = do   mx <- HT.lookup k (keysMap xs)-  pure (fst <$> mx)+  pure $! indexedTime <$> mx +{-# INLINEABLE timeOf #-}+ ageOf :: ( Hashable k          , Eq k          ) => k -> TimeMap k a -> IO (Maybe NominalDiffTime) ageOf k xs = do   now <- getCurrentTime-  mt  <- atomically (timeOf k xs)-  pure (diffUTCTime now <$> mt)+  mt  <- atomically $! timeOf k xs+  pure $! diffUTCTime now <$> mt +{-# INLINEABLE ageOf #-}  -- | Updates or deletes the value at @k@, while updating its time. update :: ( Hashable k@@ -130,17 +166,26 @@           ) => (a -> Maybe a) -> k -> TimeMap k a -> IO () update p k xs = do   now <- getCurrentTime-  atomically $ HT.focus (go now) k (keysMap xs)+  atomically $ updateWithTime now p k xs++{-# INLINEABLE update #-}++updateWithTime :: ( Hashable k+                  , Eq k+                  ) => UTCTime -> (a -> Maybe a) -> k -> TimeMap k a -> STM ()+updateWithTime now p k xs =+  HT.focus go k (keysMap xs)   where-    go _ Nothing = pure ((), F.Keep)-    go now (Just (oldTime, y)) =+    go Nothing = pure ((), F.Keep)+    go (Just (TimeIndexed oldTime y)) =       let (action,minsert) =             case p y of-              Nothing -> (F.Remove           , MM.remove oldTime k)-              Just y' -> (F.Replace (now, y'), id)+              Nothing -> (F.Remove                      , MM.remove oldTime k)+              Just y' -> (F.Replace (TimeIndexed now y'), id)       in do modifyTVar (timeMap xs) (MM.insert now k . minsert)             pure ((), action) +{-# INLINEABLE updateWithTime #-}   -- | Adjusts the value at @k@, while updating its time.@@ -149,34 +194,45 @@           ) => (a -> a) -> k -> TimeMap k a -> IO () adjust f k xs = do   now <- getCurrentTime-  atomically $ HT.focus (go now) k (keysMap xs)+  atomically $ adjustWithTime now f k xs++{-# INLINEABLE adjust #-}++adjustWithTime :: ( Hashable k+                  , Eq k+                  ) => UTCTime -> (a -> a) -> k -> TimeMap k a -> STM ()+adjustWithTime now f k xs =+  HT.focus go k (keysMap xs)   where-    go _ Nothing = pure ((), F.Keep)-    go now (Just (oldTime, y)) = do+    go Nothing = pure ((), F.Keep)+    go (Just (TimeIndexed oldTime y)) = do       modifyTVar (timeMap xs) (MM.insert now k . MM.remove oldTime k)-      pure ((), F.Replace (now, f y))+      pure ((), F.Replace (TimeIndexed now $! f y)) +{-# INLINEABLE adjustWithTime #-} + -- | Deletes the value at @k@. delete :: ( Hashable k           , Eq k           ) => k -> TimeMap k a -> STM ()-delete k xs = do-  HT.focus go k (keysMap xs)+delete k xs = HT.focus go k (keysMap xs)   where     go mx = do       case mx of-        Nothing          -> pure ()-        Just (oldTime,_) -> modifyTVar' (timeMap xs) (MM.remove oldTime k)+        Nothing -> pure ()+        Just (TimeIndexed oldTime _) ->+          modifyTVar' (timeMap xs) (MM.remove oldTime k)       pure ((), F.Remove) -+{-# INLINEABLE delete #-}  filter :: ( Hashable k           , Eq k           ) => (a -> Bool) -> TimeMap k a -> STM () filter p = filterWithKey (const p) +{-# INLINEABLE filter #-}  filterWithKey :: ( Hashable k                  , Eq k@@ -187,10 +243,12 @@   where     go k = HT.focus go' k (keysMap xs)       where-        go' (Just (_,x)) | p k x     = pure ((), F.Keep)-                         | otherwise = pure ((), F.Remove)-        go' Nothing      = pure ((), F.Keep)+        go' (Just (TimeIndexed _ x))+          | p k x     = pure ((), F.Keep)+          | otherwise = pure ((), F.Remove)+        go' Nothing   = pure ((), F.Keep) +{-# INLINEABLE filterWithKey #-}  -- | Filters out all entries older than or equal to a designated time filterSince :: ( Hashable k@@ -204,9 +262,11 @@       found    = fromMaybe HS.empty mx       toRemove = MM.elems toCut `HS.union` found   writeTVar (timeMap xs) result-  mapM_ (\k -> HT.delete k $ keysMap xs) (HS.toList toRemove)+  mapM_ (\k -> HT.delete k $ keysMap xs) $! HS.toList toRemove +{-# INLINEABLE filterSince #-} + -- | Filters out all entries within some time frame -- --   > filterFromNow 1 -- removes entities older than or equal to one second from now@@ -217,4 +277,6 @@                    -> IO () filterFromNow t xs = do   now <- getCurrentTime-  atomically $ filterSince (addUTCTime (negate t) now) xs+  atomically $ (filterSince $! addUTCTime (negate t) now) xs++{-# INLINEABLE filterFromNow #-}
src/Data/TimeMap/Internal.hs view
@@ -1,8 +1,8 @@ module Data.TimeMap.Internal where  import Data.Hashable (Hashable)-import qualified Data.Map     as Map-import qualified Data.HashSet as HS+import qualified Data.Map.Strict as Map+import qualified Data.HashSet    as HS   type MultiMap k a = Map.Map k (HS.HashSet a)@@ -17,6 +17,8 @@           ) => k -> a -> MultiMap k a -> MultiMap k a insert k x = Map.insertWith (HS.union) k (HS.singleton x) +{-# INLINEABLE insert #-}+ lookup :: ( Ord k           ) => k -> MultiMap k a -> HS.HashSet a lookup k xs =@@ -24,11 +26,15 @@     Nothing -> HS.empty     Just ys -> ys +{-# INLINEABLE lookup #-}+ -- | Deletes all elements at @k@ delete :: ( Ord k           ) => k -> MultiMap k a -> MultiMap k a delete = Map.delete +{-# INLINEABLE delete #-}+ -- | Deletes only the element @a@ from the referenced key @k@ remove :: ( Ord k           , Hashable a@@ -41,7 +47,20 @@               then Nothing               else Just s' +{-# INLINEABLE remove #-}+ elems :: ( Hashable a          , Eq a          ) => MultiMap k a -> HS.HashSet a elems = foldr HS.union HS.empty++{-# INLINEABLE elems #-}++toList :: ( Hashable a+          , Eq a+          ) => MultiMap k a -> [(k, a)]+toList =+  Map.foldrWithKey go []+  where+    go :: k -> HS.HashSet a -> [(k, a)] -> [(k, a)]+    go k x acc = repeat k `zip` HS.toList x ++ acc
timemap.cabal view
@@ -1,5 +1,5 @@ Name:                   timemap-Version:                0.0.2+Version:                0.0.3 Author:                 Athan Clark <athan.clark@gmail.com> Maintainer:             Athan Clark <athan.clark@gmail.com> License:                BSD3