forked from mgsloan/ActiveHs
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCache.hs
More file actions
70 lines (54 loc) · 1.7 KB
/
Copy pathCache.hs
File metadata and controls
70 lines (54 loc) · 1.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
-- | A very simple cache
module Cache
( Cache
, newCache
, lookupCache
, clearCache
) where
import Hash
import Control.Concurrent.MVar (MVar, newEmptyMVar, readMVar, putMVar)
import Data.Array.IO (IOArray, newArray, readArray, writeArray, getBounds)
import Data.Char (digitToInt)
-------------------------
data Cache a
= Cache
{ array :: IOArray Int [CacheEntry a]
, cacheLineSize :: Int -- length of the lists
}
data CacheEntry a
= CacheEntry
{ question :: Hash
, answer :: MVar a
}
newCache :: Int -> IO (Cache a)
newCache x = do
a <- newArray (0,255) []
return $ Cache a x
clearCache :: Cache a -> IO ()
clearCache c = do
(a,b) <- getBounds $ array c
mapM_ (\i -> writeArray (array c) i []) [a..b]
lookupCache :: Cache a -> Hash -> IO (Either a (a -> IO ()))
lookupCache ch e = modifyCacheLine (array ch) (getIndex e) $ \vv ->
case lookupIA (cacheLineSize ch) (\x -> e == question x) vv of
(Just x_, c) -> do
x <- readMVar (answer x_)
return (x_ : c, Left x)
(Nothing, c) -> do
v <- newEmptyMVar
return (CacheEntry e v: c, Right $ putMVar v)
where
lookupIA :: Int -> (a -> Bool) -> [a] -> (Maybe a, [a])
lookupIA i p l = f i l where
f _ (x: xs) | p x = (Just x, xs)
f 1 _ = (Nothing, [])
f i (x: xs) = case f (i-1) xs of
(a, b) -> (a, x:b)
f _ [] = (Nothing, [])
modifyCacheLine ch i f = do
x <- readArray ch i
(x', r) <- f x
writeArray ch i x'
return r
getIndex :: Hash -> Int
getIndex e = 16 * digitToInt a + digitToInt b where (a:b:_) = show e