module Data.Concurrent.Bag(Bag, Token, new, put, remove, foreach) where
import Control.Monad
import Control.Concurrent
import System.IO.Unsafe (unsafePerformIO)
import Data.IORef
import qualified Data.IntMap as M
type UID = Int
type Token a = (Bag a, UID)
type Bag a = IORef (M.IntMap a)
atomicIncr :: IORef Int -> IO Int
atomicIncr cntr = atomicModifyIORef' cntr (\c -> (c+1,c))
uidCntr :: IORef UID
uidCntr = unsafePerformIO (newIORef 0)
getUID :: IO UID
getUID = atomicIncr uidCntr
new :: IO (Bag a)
new = newIORef (M.empty)
put :: Bag a -> a -> IO (Token a)
put b x = do
uid <- getUID
atomicModifyIORef' b $ \m -> (M.insert uid x m, ())
return (b, uid)
foreach :: Bag a -> (a -> Token a -> IO ()) -> IO ()
foreach b f = do
m <- readIORef b
let invoke (k, a) = f a (b, k)
mapM_ invoke $ M.toList m
remove :: Token a -> IO ()
remove (b, uid) = atomicModifyIORef' b $ \m -> (M.delete uid m, ())