packages feed

stm-hamt-1.2.0.10: test/Main/Transaction.hs

module Main.Transaction where

import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as Text
import Focus (Focus (..))
import qualified Focus
import StmHamt.Hamt (Hamt)
import qualified StmHamt.Hamt as StmHamt
import Prelude

data Transaction = forall result.
  (Show result, Eq result) =>
  Transaction
  { name :: Text,
    applyToHashMap :: HashMap Text Int -> (result, HashMap Text Int),
    applyToStmHamt :: Hamt (Text, Int) -> STM result
  }

instance Show Transaction where
  show = Text.unpack . name

lookup :: Text -> Transaction
lookup key =
  let name = fromString ("lookup " <> show key)
      applyToHashMap hashMap = (HashMap.lookup key hashMap, hashMap)
      applyToStmHamt hamt = (fmap . fmap) snd (StmHamt.lookup fst key hamt)
   in Transaction name applyToHashMap applyToStmHamt

insert :: Text -> Int -> Transaction
insert key value =
  let name = fromString ("insert " <> show key <> " " <> show value)
      applyToHashMap = ((),) . HashMap.insert key value
      applyToStmHamt hamt = StmHamt.insert fst (key, value) hamt $> ()
   in Transaction name applyToHashMap applyToStmHamt

-- | A transaction which can be used to manipulate hash collision
insertWithHash :: Int -> Text -> Int -> Transaction
insertWithHash hash key value =
  let name = fromString ("insert " <> show key <> " " <> show value)
      applyToHashMap = ((),) . HashMap.insert key value
      applyToStmHamt hamt = StmHamt.insertExplicitly hash ((==) key . fst) (key, value) hamt $> ()
   in Transaction name applyToHashMap applyToStmHamt

focus :: (forall m. (Monad m) => Focus Int m ()) -> Text -> Transaction
focus focus@(Focus conceal reveal) key =
  let name = "focus"
      applyToHashMap hashMap =
        let Identity (result, change) = case HashMap.lookup key hashMap of
              Just existingValue -> reveal existingValue
              Nothing -> conceal
            newHashMap = case change of
              Focus.Leave -> hashMap
              Focus.Set newValue -> HashMap.insert key newValue hashMap
              Focus.Remove -> HashMap.delete key hashMap
         in (result, newHashMap)
      applyToStmHamt =
        let stmHamtFocus = Focus.mappingInput (key,) snd focus
         in StmHamt.focus stmHamtFocus fst key
   in Transaction name applyToHashMap applyToStmHamt

insertUsingFocus :: Text -> Int -> Transaction
insertUsingFocus key value =
  let name = fromString ("insertUsingFocus " <> show key <> " " <> show value)
   in (focus (Focus.insert value) key) {name = name}

deleteUsingFocus :: Text -> Transaction
deleteUsingFocus key =
  let name = fromString ("deleteUsingFocus " <> show key)
   in (focus Focus.delete key) {name = name}

incrementUsingAdjustFocus :: Text -> Transaction
incrementUsingAdjustFocus key =
  let name = fromString ("incrementUsingAdjustFocus " <> show key)
   in (focus (Focus.adjust succ) key) {name = name}