packages feed

stm-containers-0.2.3: executables/WordArrayTests/Update.hs

module WordArrayTests.Update where

import Test.Framework
import STMContainers.Prelude
import MTLPrelude
import Control.Monad.Free
import Control.Monad.Free.TH
import qualified STMContainers.WordArray as WordArray


data UpdateF e f =
  Singleton Int e f |
  Set Int e f |
  Unset Int f
  deriving (Functor)

makeFree ''UpdateF

newtype Update e r = Update (Free (UpdateF e) r)

instance Show (Update e r) where
  show = const "<Update>"

instance Arbitrary (Update Char ()) where
  arbitrary = do
    i <- bit
    v <- char
    fmap Update $ build $ singleton i v
    where
      build = execStateT $ do
        amount <- lift $ choose (0, 200)
        replicateM_ amount $ do
          lift (choose (0 :: Int, 1)) >>= \case
            0 -> do
              i <- lift $ bit
              v <- lift $ char
              modify (>> set i v)
            1 -> do
              i <- lift $ bit
              modify (>> unset i)
      char = fmap chr $ choose (ord 'a', ord 'z')
      bit = choose (0, pred wordSize)

interpretWordArray :: Update e () -> Maybe (WordArray.WordArray e)
interpretWordArray (Update u) = 
  flip execState Nothing $ flip iterM u $ \case
    Singleton i e f -> do
      put $ Just $ WordArray.singleton i e
      f
    Set i e f -> get >>= put . fmap (WordArray.set i e) >> f
    Unset i f -> get >>= put . fmap (WordArray.unset i) >> f

interpretMaybeList :: Update e () -> Maybe [Maybe e]
interpretMaybeList (Update u) = 
  flip execState Nothing $ flip iterM u $ \case
    Singleton i e f -> do
      put $ Just $ map (\i' -> if i == i' then Just e else Nothing) [0 .. pred wordSize]
      f
    Set i e f -> do
      lm <- get
      lm' <- forM lm $ \l -> 
        return $ do
          (i', e') <- zip [0..] l
          return $ if i == i' then Just e else e'
      put lm'
      f
    Unset i f -> do
      lm <- get
      put $ flip fmap lm $ \l -> do
        (i', e') <- zip [0..] l
        return $ if i == i' then Nothing else e'
      f

wordSize :: Int
wordSize = bitSize (undefined :: Word)