|
| 1 | +{-# LANGUAGE GeneralizedNewtypeDeriving #-} |
| 2 | +-- | Test utilities |
| 3 | +module Utils |
| 4 | + ( Key (..) |
| 5 | + , Expr (..) |
| 6 | + , evalExprStrict |
| 7 | + , evalExprLazy |
| 8 | + , evalExprSet |
| 9 | + , evalExprOrdSet |
| 10 | + ) where |
| 11 | + |
| 12 | +import Control.Applicative (liftA2, liftA3) |
| 13 | +import Data.Hashable (Hashable(hashWithSalt)) |
| 14 | +import Test.QuickCheck (Arbitrary(arbitrary,shrink), oneof, sized) |
| 15 | + |
| 16 | +import qualified Data.HashMap.Strict as HMS |
| 17 | +import qualified Data.HashMap.Lazy as HML |
| 18 | +import qualified Data.HashSet as HS |
| 19 | +import qualified Data.Set as Set |
| 20 | + |
| 21 | +-- | A key with collision-prone Hashable instance |
| 22 | +------------------------------------------------------------------------ |
| 23 | + |
| 24 | +-- Key type that generates more hash collisions. |
| 25 | +newtype Key = K { unK :: Int } |
| 26 | + deriving (Arbitrary, Enum, Eq, Ord, Read, Show, Integral, Num, Real) |
| 27 | + |
| 28 | +instance Hashable Key where |
| 29 | + hashWithSalt salt k = hashWithSalt salt (unK k) `mod` 20 |
| 30 | + |
| 31 | +-- | A HashMap/HashSet building expression |
| 32 | +------------------------------------------------------------------------ |
| 33 | + |
| 34 | +data Expr k v |
| 35 | + = ExprEmpty |
| 36 | + | ExprSingleton k v |
| 37 | + | ExprInsert k v (Expr k v) |
| 38 | + | ExprDelete k (Expr k v) |
| 39 | + | ExprUnion (Expr k v) (Expr k v) |
| 40 | + deriving Show |
| 41 | + |
| 42 | +instance (Arbitrary k, Arbitrary v) => Arbitrary (Expr k v) where |
| 43 | + arbitrary = sized arb |
| 44 | + where |
| 45 | + arb n | n <= 0 = oneof leafs |
| 46 | + arb n = oneof $ leafs ++ |
| 47 | + [ liftA3 ExprInsert arbitrary arbitrary (arb (n - 1)) |
| 48 | + , liftA2 ExprDelete arbitrary (arb (n - 1)) |
| 49 | + , liftA2 ExprUnion (arb (n `div` 2)) (arb (n - n `div` 2)) |
| 50 | + ] |
| 51 | + |
| 52 | + leafs = |
| 53 | + [ return ExprEmpty |
| 54 | + , liftA2 ExprSingleton arbitrary arbitrary |
| 55 | + ] |
| 56 | + |
| 57 | + shrink ExprEmpty |
| 58 | + = [] |
| 59 | + shrink (ExprSingleton k v) = |
| 60 | + ExprEmpty : uncurry ExprSingleton `map` shrink (k, v) |
| 61 | + shrink (ExprInsert k v e) = |
| 62 | + ExprEmpty : e : uncurry3 ExprInsert `map` shrink (k, v, e) |
| 63 | + shrink (ExprDelete k e) = |
| 64 | + ExprEmpty : e : uncurry ExprDelete `map` shrink (k, e) |
| 65 | + shrink (ExprUnion a b) = |
| 66 | + ExprEmpty : a : b : uncurry ExprUnion `map` shrink (a, b) |
| 67 | + |
| 68 | +uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d |
| 69 | +uncurry3 f (a, b, c) = f a b c |
| 70 | + |
| 71 | +evalExprStrict :: (Eq k, Hashable k) => Expr k v -> HMS.HashMap k v |
| 72 | +evalExprStrict = go |
| 73 | + where |
| 74 | + go ExprEmpty = HMS.empty |
| 75 | + go (ExprSingleton k v) = HMS.singleton k v |
| 76 | + go (ExprInsert k v e) = HMS.insert k v (go e) |
| 77 | + go (ExprDelete k e) = HMS.delete k (go e) |
| 78 | + go (ExprUnion a b) = HMS.union (go a) (go b) |
| 79 | + |
| 80 | +evalExprLazy :: (Eq k, Hashable k) => Expr k v -> HML.HashMap k v |
| 81 | +evalExprLazy = go |
| 82 | + where |
| 83 | + go ExprEmpty = HML.empty |
| 84 | + go (ExprSingleton k v) = HML.singleton k v |
| 85 | + go (ExprInsert k v e) = HML.insert k v (go e) |
| 86 | + go (ExprDelete k e) = HML.delete k (go e) |
| 87 | + go (ExprUnion a b) = HML.union (go a) (go b) |
| 88 | + |
| 89 | +evalExprSet :: (Eq k, Hashable k) => Expr k () -> HS.HashSet k |
| 90 | +evalExprSet = go |
| 91 | + where |
| 92 | + go ExprEmpty = HS.empty |
| 93 | + go (ExprSingleton k _) = HS.singleton k |
| 94 | + go (ExprInsert k _ e) = HS.insert k (go e) |
| 95 | + go (ExprDelete k e) = HS.delete k (go e) |
| 96 | + go (ExprUnion a b) = HS.union (go a) (go b) |
| 97 | + |
| 98 | +evalExprOrdSet :: (Ord k) => Expr k () -> Set.Set k |
| 99 | +evalExprOrdSet = go |
| 100 | + where |
| 101 | + go ExprEmpty = Set.empty |
| 102 | + go (ExprSingleton k _) = Set.singleton k |
| 103 | + go (ExprInsert k _ e) = Set.insert k (go e) |
| 104 | + go (ExprDelete k e) = Set.delete k (go e) |
| 105 | + go (ExprUnion a b) = Set.union (go a) (go b) |
0 commit comments