1 % $Id: Memo.lhs,v 1.1 1999/02/03 16:54:02 simonm Exp $
3 % (c) The GHC Team, 1999
8 {-# OPTIONS -fglasgow-exts #-}
11 ( memo -- :: (a -> b) -> a -> b
12 , memo_sized -- :: Int -> (a -> b) -> a -> b
22 -----------------------------------------------------------------------------
23 Memo table representation.
25 The representation is this: a fixed-size hash table where each bucket
26 is a list of table entries, of the form (key,value).
28 The key in this case is (StableName key), and we use hashStableName to
31 It's important that we can garbage collect old entries in the table
32 when the key is no longer reachable in the heap. Hence the value part
33 of each table entry is (Weak val), where the weak pointer "key" is the
34 key for our memo table, and 'val' is the value of this memo table
35 entry. When the key becomes unreachable, a finaliser will fire and
36 remove this entry from the hash bucket, and further attempts to
37 dereference the weak pointer will return Nothing. References from
38 'val' to the key are ignored (see the semantics of weak pointers in
42 type MemoTable key val
44 Int, -- current table size
45 IOArray Int [(StableName key, Weak val)] -- hash table
49 We use an MVar to the hash table, so that several threads may safely
50 access it concurrently. This includes the finalisation threads that
51 remove entries from the table.
53 ToDo: make the finalisers refer to the memo table only through a weak
54 pointer, because otherwise the memo table will keep itself alive
55 (i.e. even after the function is dead, the weak pointers in the memo
56 table stay alive because their keys are alive, and hence the values
57 and finalisers are alive, therefore the table itself stays alive.
61 memo :: (a -> b) -> a -> b
62 memo f = memo_sized default_table_size f
64 default_table_size = 1001
66 memo_sized :: Int -> (a -> b) -> a -> b
68 let table = unsafePerformIO (do
69 tbl <- newIOArray (0,1001) [];
73 memo' :: (a -> b) -> MemoTable a b -> a -> b
74 memo' f ref = \x -> unsafePerformIO $ do
75 stable_key <- makeStableName x
76 (size, table) <- takeMVar ref
77 let hash_key = hashStableName stable_key `mod` size
78 bucket <- readIOArray table hash_key
79 lkp <- lookupSN stable_key bucket
83 putMVar ref (size,table)
87 weak <- mkWeak x result finaliser
88 writeIOArray table hash_key ((stable_key,weak):bucket)
89 putMVar ref (size,table)
93 (size,table) <- takeMVar ref
94 bucket <- readIOArray table hash_key
95 let new_bucket = [ (sn,weak)
96 | (sn,weak) <- bucket,
98 writeIOArray table hash_key new_bucket
99 putMVar ref (size,table)
101 lookupSN :: StableName key -> [(StableName key, Weak val)] -> IO (Maybe val)
102 lookupSN sn [] = return Nothing
103 lookupSN sn ((sn',weak) : xs)
104 | sn == sn' = do maybe_item <- deRefWeak weak
106 Nothing -> error ("dead weak pair: " ++
107 show (hashStableName sn))
108 Just v -> return (Just v)
109 | otherwise = lookupSN sn xs