| 1 | type HashIndex = VStr |
|---|
| 2 | |
|---|
| 3 | class (Typeable a) => HashClass a where |
|---|
| 4 | hash_iType :: a -> Type |
|---|
| 5 | hash_iType = const $ mkType "Hash" |
|---|
| 6 | hash_fetch :: a -> Eval VHash |
|---|
| 7 | hash_fetch hv = do |
|---|
| 8 | keys <- hash_fetchKeys hv |
|---|
| 9 | vals <- mapM (hash_fetchVal hv) keys |
|---|
| 10 | let ps = keys `zip` vals |
|---|
| 11 | return (length ps `seq` Map.fromList ps) |
|---|
| 12 | hash_store :: a -> VHash -> Eval () |
|---|
| 13 | hash_store hv vals = do |
|---|
| 14 | hash_clear hv |
|---|
| 15 | forM_ (Map.assocs vals) $ \(key, val) -> do |
|---|
| 16 | hash_storeVal hv key val |
|---|
| 17 | hash_fetchElem :: a -> HashIndex -> Eval (IVar VScalar) -- autovivify |
|---|
| 18 | hash_fetchElem hv key = do |
|---|
| 19 | return $ proxyScalar (hash_fetchVal hv key) (hash_storeVal hv key) |
|---|
| 20 | hash_storeElem :: a -> HashIndex -> IVar VScalar -> Eval () -- binding |
|---|
| 21 | hash_storeElem hv idx sv = do |
|---|
| 22 | val <- readIVar sv |
|---|
| 23 | hash_storeVal hv idx val |
|---|
| 24 | hash_fetchVal :: a -> HashIndex -> Eval Val |
|---|
| 25 | hash_fetchVal hv key = do |
|---|
| 26 | rv <- hash_existsElem hv key |
|---|
| 27 | if rv then readIVar =<< hash_fetchElem hv key |
|---|
| 28 | else return undef |
|---|
| 29 | hash_storeVal :: a -> HashIndex -> Val -> Eval () |
|---|
| 30 | hash_storeVal hv key val = do |
|---|
| 31 | sv <- hash_fetchElem hv key |
|---|
| 32 | writeIVar sv val |
|---|
| 33 | hash_fetchKeys :: a -> Eval [HashIndex] |
|---|
| 34 | hash_fetchKeys hv = do |
|---|
| 35 | vals <- hash_fetch hv |
|---|
| 36 | return $ Map.keys vals |
|---|
| 37 | hash_fetchSize :: a -> Eval Int |
|---|
| 38 | hash_fetchSize hv = do |
|---|
| 39 | vals <- hash_fetch hv |
|---|
| 40 | return $ Map.size vals |
|---|
| 41 | hash_deleteElem :: a -> HashIndex -> Eval () |
|---|
| 42 | hash_existsElem :: a -> HashIndex -> Eval VBool |
|---|
| 43 | hash_existsElem hv idx = do |
|---|
| 44 | keys <- hash_fetchKeys hv |
|---|
| 45 | return $ idx `elem` keys |
|---|
| 46 | hash_clear :: a -> Eval () |
|---|
| 47 | hash_clear hv = do |
|---|
| 48 | keys <- hash_fetchKeys hv |
|---|
| 49 | mapM_ (hash_deleteElem hv) keys |
|---|
| 50 | hash_isEmpty :: a -> Eval VBool |
|---|
| 51 | hash_isEmpty hv = do |
|---|
| 52 | keys <- hash_fetchKeys hv |
|---|
| 53 | return $ null keys |
|---|
| 54 | hash_clone :: a -> STM a |
|---|
| 55 | hash_clone = return |
|---|
| 56 | |
|---|
| 57 | instance HashClass (IVar VPair) where |
|---|
| 58 | hash_iType = const $ mkType "Pair" |
|---|
| 59 | hash_fetch pv = do |
|---|
| 60 | (k, v) <- readIVar pv |
|---|
| 61 | str <- fromVal k |
|---|
| 62 | return $ Map.singleton str v |
|---|
| 63 | hash_fetchVal pv idx = do |
|---|
| 64 | (k, v) <- readIVar pv |
|---|
| 65 | str <- fromVal k |
|---|
| 66 | if str == idx |
|---|
| 67 | then return v |
|---|
| 68 | else return undef |
|---|
| 69 | hash_storeVal _ _ _ = retConstError undef |
|---|
| 70 | hash_deleteElem _ _ = retConstError undef |
|---|
| 71 | |
|---|
| 72 | instance HashClass VHash where |
|---|
| 73 | hash_iType = const $ mkType "Hash::Const" |
|---|
| 74 | hash_fetch = return |
|---|
| 75 | hash_fetchKeys = return . Map.keys |
|---|
| 76 | hash_fetchVal hv idx = return $ Map.findWithDefault undef idx hv |
|---|
| 77 | hash_clear _ = retConstError undef |
|---|
| 78 | hash_store _ _ = retConstError undef |
|---|
| 79 | hash_storeVal _ _ _ = retConstError undef |
|---|
| 80 | hash_storeElem _ _ _ = retConstError undef |
|---|
| 81 | hash_deleteElem _ _ = retConstError undef |
|---|
| 82 | |
|---|
| 83 | instance HashClass IHashEnv where |
|---|
| 84 | hash_iType = const $ mkType "Hash::Env" |
|---|
| 85 | hash_fetch _ = do |
|---|
| 86 | envs <- io getEnvironment |
|---|
| 87 | return . Map.map (VStr . decodeUTF8) $ Map.fromList envs |
|---|
| 88 | hash_fetchVal _ key = tryIO undef $ do |
|---|
| 89 | str <- getEnv key |
|---|
| 90 | return $ fromMaybe VUndef (fmap (VStr . decodeUTF8) str) |
|---|
| 91 | hash_storeVal _ key val = do |
|---|
| 92 | str <- fromVal val |
|---|
| 93 | io $ setEnv key (encodeUTF8 str) True |
|---|
| 94 | hash_existsElem _ key = tryIO False $ do |
|---|
| 95 | str <- getEnv key |
|---|
| 96 | return (isJust str) |
|---|
| 97 | hash_deleteElem _ key = do |
|---|
| 98 | io $ unsetEnv key |
|---|
| 99 | |
|---|
| 100 | encodeKey, decodeKey :: HashIndex -> HashIndex |
|---|
| 101 | encodeKey x = x |
|---|
| 102 | decodeKey x = x |
|---|
| 103 | |
|---|
| 104 | instance HashClass IHash where |
|---|
| 105 | hash_iType = const $ mkType "Hash" |
|---|
| 106 | hash_clone hv = do |
|---|
| 107 | ps <- unsafeIOToSTM $ H.toList hv |
|---|
| 108 | ps' <- forM ps $ \(k, sv) -> do |
|---|
| 109 | sv' <- cloneIVar sv |
|---|
| 110 | return (k, sv') |
|---|
| 111 | unsafeIOToSTM $ H.fromList H.hashString ps' |
|---|
| 112 | hash_fetch hv = do |
|---|
| 113 | ps <- io $ H.toList hv |
|---|
| 114 | ps' <- forM ps $ \(k, sv) -> do |
|---|
| 115 | val <- readIVar sv |
|---|
| 116 | return (decodeKey k, val) |
|---|
| 117 | return (length ps' `seq` Map.fromList ps') |
|---|
| 118 | hash_fetchKeys hv = do |
|---|
| 119 | fmap (map (decodeKey . fst)) (io $ H.toList hv) |
|---|
| 120 | hash_fetchElem hv idx = do |
|---|
| 121 | let idx' = encodeKey idx |
|---|
| 122 | r <- io $ H.lookup hv idx' |
|---|
| 123 | case r of |
|---|
| 124 | Just sv -> return sv |
|---|
| 125 | Nothing -> do |
|---|
| 126 | sv <- newScalar undef |
|---|
| 127 | io $ H.insert hv idx' sv |
|---|
| 128 | return sv |
|---|
| 129 | hash_storeElem hv idx sv = do |
|---|
| 130 | io $ H.insert hv (encodeKey idx) sv |
|---|
| 131 | hash_deleteElem hv idx = do |
|---|
| 132 | io $ H.delete hv (encodeKey idx) |
|---|
| 133 | return () |
|---|
| 134 | hash_existsElem hv idx = do |
|---|
| 135 | io $ fmap isJust (H.lookup hv (encodeKey idx)) |
|---|
| 136 | |
|---|
| 137 | instance HashClass PerlSV where |
|---|
| 138 | hash_iType = const $ mkType "Hash::Perl" |
|---|
| 139 | hash_fetchVal sv key = do |
|---|
| 140 | keySV <- fromVal $ castV key |
|---|
| 141 | perl5EvalApply "sub { $_[0]->{$_[1]} }" [sv, keySV] |
|---|
| 142 | hash_clear sv = do |
|---|
| 143 | perl5EvalApply "sub { undef %{$_[0]} }" [sv] |
|---|
| 144 | return () |
|---|
| 145 | hash_storeVal sv key val = do |
|---|
| 146 | keySV <- fromVal $ castV key |
|---|
| 147 | valSV <- fromVal val |
|---|
| 148 | perl5EvalApply "sub { $_[0]->{$_[1]} = $_[2] }" [sv, keySV, valSV] |
|---|
| 149 | return () |
|---|
| 150 | hash_fetchKeys sv = do |
|---|
| 151 | keysSV <- perl5EvalApply "sub { join $/, keys %{$_[0]} }" [sv] |
|---|
| 152 | keysStr <- fromVal keysSV |
|---|
| 153 | return $ lines keysStr |
|---|
| 154 | hash_deleteElem sv key = do |
|---|
| 155 | keySV <- fromVal $ castV key |
|---|
| 156 | perl5EvalApply "sub { delete $_[0]->{$_[1]} }" [sv, keySV] |
|---|
| 157 | return () |
|---|
| 158 | hash_isEmpty sv = do |
|---|
| 159 | fromVal =<< perl5EvalApply "sub { !!%{$_[0]} }" [sv] |
|---|