packages feed

ref-extras 0.1.0 → 0.1.1

raw patch · 2 files changed

+73/−2 lines, 2 filesdep +hashabledep +unordered-containers

Dependencies added: hashable, unordered-containers

Files

ref-extras.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 9e81744739214454e5314bea860635661caf7b4f4296bb4c6f873e105c986c45+-- hash: 0c53a1b53092126beb62eea99bfb47ad42c02b42aef27681ee3434592b29b682  name:           ref-extras-version:        0.1.0+version:        0.1.1 synopsis:       Extra stuff for mutable references description:    Please see the README on GitHub at <https://github.com/ejconlon/ref-extras#readme> category:       Data@@ -32,6 +32,7 @@       RefExtras.Classes       RefExtras.EVar       RefExtras.LensRef+      RefExtras.Memo       RefExtras.SomeRef       RefExtras.XVar   other-modules:@@ -42,9 +43,11 @@   ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints -fno-warn-unused-top-binds   build-depends:       base >=4.12 && <5+    , hashable >=1.3     , little-rio >=0.1.1     , microlens >=0.4     , stm >=2.5     , unliftio >=0.2     , unliftio-core >=0.1+    , unordered-containers >=0.2   default-language: Haskell2010
+ src/RefExtras/Memo.hs view
@@ -0,0 +1,68 @@+module RefExtras.Memo+  ( Memo+  , accessMemo+  , clearMemo+  , freezeMemo+  , newMemo+  , thawMemo+  , tryReadMemo+  , writeMemo+  ) where++import Control.Monad (join)+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.IO.Unlift (MonadUnliftIO)+import Data.Hashable (Hashable)+import Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as HashMap+import Prelude+import RefExtras.EVar (EVar, accessEVar, newEventualEVar, newReadyEVar, tryReadEVar, writeEVar)+import RefExtras.XVar (XVar, newXVar, readXVar, splitXVar, writeXVar)++newtype Memo k a = Memo { unMemo :: XVar (HashMap k (EVar a)) }++newMemo :: MonadIO m => m (Memo k a)+newMemo = fmap Memo (newXVar HashMap.empty)++clearMemo :: MonadIO m => Memo k a -> m ()+clearMemo (Memo v) = writeXVar v HashMap.empty++accessMemo :: (MonadUnliftIO m, Eq k, Hashable k) => Memo k a -> k -> m a -> m a+accessMemo (Memo v) k act = splitXVar v $ \m write ->+  case HashMap.lookup k m of+    Just w -> write m >> accessEVar w act+    Nothing -> newEventualEVar (\w -> write (HashMap.insert k w m)) act++tryReadMemo :: (MonadIO m, Eq k, Hashable k) => Memo k a -> k -> m (Maybe a)+tryReadMemo (Memo v) k = do+  m <- readXVar v+  case HashMap.lookup k m of+    Nothing -> pure Nothing+    Just w -> tryReadEVar w++-- Blocks if k is being populated+writeMemo :: (MonadUnliftIO m, Eq k, Hashable k) => Memo k a -> k -> a -> m ()+writeMemo (Memo v) k a = splitXVar v $ \m write ->+  case HashMap.lookup k m of+    Just w -> write m >> writeEVar w a+    Nothing -> do+      w <- newReadyEVar a+      write (HashMap.insert k w m)++bindFor :: (Monad t, Traversable t, Applicative f) => t a -> (a -> f (t b)) -> f (t b)+bindFor t f = fmap join (traverse f t)++freezeMemo :: (MonadIO m, Eq k, Hashable k) => Memo k a -> m (HashMap k a)+freezeMemo (Memo v) = do+  m <- readXVar v+  fmap HashMap.fromList $ bindFor (HashMap.toList m) $ \(k, w) -> do+    ma <- tryReadEVar w+    case ma of+      Just a -> pure [(k, a)]+      _ -> pure []++thawMemo :: MonadIO m => HashMap k a -> m (Memo k a)+thawMemo m = do+  n <- traverse newReadyEVar m+  v <- newXVar n+  pure (Memo v)