1 {-# LANGUAGE ScopedTypeVariables #-}
3 ( RefObj(..), PrintableRef(..), traverseIO, markTree''
4 {- dont export generic versions for high performance -> remove for production -}) where
7 import qualified Data.Set as S
9 import Foreign.Ptr (IntPtr, Ptr)
11 class (Eq a, Ord a) => RefObj a where
13 payload :: a -> IO IntPtr
18 patchRefs :: a -> [a] -> IO ()
19 newRef :: a -> a -> IO ()
21 marked :: a -> IO Bool
26 class PrintableRef a where
27 printRef :: a -> IO ()
29 -- | Generically marks a graph (can be used to set mark bit and reset mark bit at the same time
30 -- using customized loopcheck and marker funcs (i.e. to set the bit check on ==1 and on ==0 otherwise)
31 -- Furthermore it produces a list of visited nodes (this can be all live one (or dead on respectively)
32 markTree'' :: RefObj a => (a -> IO Bool) -> (a -> IO ()) -> [a] -> a -> IO [a]
33 markTree'' loopcheck marker ws root = do loop <- loopcheck root
34 if loop then return ws else liftM (root :) continue
35 where continue = marker root >> refs root >>= foldM (markTree'' loopcheck marker) ws
37 -- | For debugging only (implements custom loop check with Data.Set!)
38 traverseIO :: RefObj o => (o -> IO ()) -> o -> IO ()
39 traverseIO f = void . traverseIO' f S.empty
41 traverseIO' :: RefObj a => (a -> IO ()) -> S.Set a -> a -> IO (S.Set a)
42 traverseIO' f ws root = if S.member root ws then f root >> return ws
43 else f root >> refs root >>= cont
44 where cont = foldM (\ws x -> do let ws' = S.insert x ws
45 traverseIO' f ws' x) ws'
46 ws' = S.insert root ws
48 markTree :: RefObj a => a -> IO ()
49 markTree root = marked root >>= (`unless` continue)
50 where continue = mark root >> refs root >>= mapM_ markTree